Merge "lsm: add support for SVA multi sound model"

This commit is contained in:
qctecmdr 2020-06-09 09:24:19 -07:00 • committed by Gerrit - the friendly Code Review server
commit 6c188e55ac
4 changed files with 510 additions and 188 deletions

View file

@ -499,38 +499,71 @@ static int msm_lsm_get_conf_levels(struct lsm_client *client,
{
int rc = 0;
if (client->num_confidence_levels == 0) {
pr_debug("%s: no confidence levels provided\n",
__func__);
client->confidence_levels = NULL;
goto done;
}
client->confidence_levels =
kzalloc((sizeof(uint8_t) * client->num_confidence_levels),
GFP_KERNEL);
if (!client->confidence_levels) {
pr_err("%s: No memory for confidence\n"
"levels num of level from user = %d\n",
__func__, client->num_confidence_levels);
rc = -ENOMEM;
if (client->num_sound_models != 0) {
if (client->num_keywords == 0) {
pr_debug("%s: no number of confidence_values provided\n",
__func__);
client->multi_snd_model_confidence_levels = NULL;
goto done;
}
}
if (copy_from_user(client->confidence_levels,
conf_levels_ptr,
client->num_confidence_levels)) {
pr_err("%s: copy from user failed, size = %d\n",
__func__, client->num_confidence_levels);
rc = -EFAULT;
goto copy_err;
}
client->multi_snd_model_confidence_levels =
kzalloc((sizeof(uint32_t) * client->num_keywords),
GFP_KERNEL);
if (!client->multi_snd_model_confidence_levels) {
pr_err("%s: No memory for confidence\n"
"levels num of level from user = %d\n",
__func__, client->num_keywords);
rc = -ENOMEM;
goto done;
}
if (copy_from_user((u8 *)client->multi_snd_model_confidence_levels,
conf_levels_ptr,
sizeof(uint32_t) * client->num_keywords)) {
pr_err("%s: copy from user failed, number of keywords = %d\n",
__func__, client->num_keywords);
rc = -EFAULT;
goto copy_err;
}
} else {
if (client->num_confidence_levels == 0) {
pr_debug("%s: no confidence levels provided\n",
__func__);
client->confidence_levels = NULL;
goto done;
}
client->confidence_levels =
kzalloc((sizeof(uint8_t) * client->num_confidence_levels),
GFP_KERNEL);
if (!client->confidence_levels) {
pr_err("%s: No memory for confidence\n"
"levels num of level from user = %d\n",
__func__, client->num_confidence_levels);
rc = -ENOMEM;
goto done;
}
if (copy_from_user(client->confidence_levels,
conf_levels_ptr,
client->num_confidence_levels)) {
pr_err("%s: copy from user failed, size = %d\n",
__func__, client->num_confidence_levels);
rc = -EFAULT;
goto copy_err;
}
}
return rc;
copy_err:
kfree(client->confidence_levels);
client->confidence_levels = NULL;
if (client->num_sound_models != 0) {
kfree(client->multi_snd_model_confidence_levels);
client->multi_snd_model_confidence_levels = NULL;
} else {
kfree(client->confidence_levels);
client->confidence_levels = NULL;
}
done:
return rc;
@ -652,35 +685,67 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
int rc = 0;
if (p_info->param_size > MAX_NUM_CONFIDENCE) {
dev_err(rtd->dev,
"%s: invalid confidence levels %d\n",
__func__, p_info->param_size);
return -EINVAL;
}
if (p_info->param_type == LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS) {
if (p_info->param_size > MAX_KEYWORDS_SUPPORTED) {
dev_err(rtd->dev,
"%s: invalid number of snd_model keywords %d, the max is %d\n",
__func__, p_info->param_size, MAX_KEYWORDS_SUPPORTED);
return -EINVAL;
}
prtd->lsm_client->num_confidence_levels =
p_info->param_size;
rc = msm_lsm_get_conf_levels(prtd->lsm_client,
p_info->param_data);
if (rc) {
dev_err(rtd->dev,
"%s: get_conf_levels failed, err = %d\n",
__func__, rc);
return rc;
}
prtd->lsm_client->num_keywords = p_info->param_size;
rc = msm_lsm_get_conf_levels(prtd->lsm_client,
p_info->param_data);
if (rc) {
dev_err(rtd->dev,
"%s: get_conf_levels failed for snd_model %d, err = %d\n",
__func__, p_info->model_id, rc);
return rc;
}
rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
prtd->lsm_client->confidence_levels,
LSM_MIN_CONFIDENCE_LEVELS);
if (rc)
dev_err(rtd->dev,
"%s: Failed to set min_conf_levels, err = %d\n",
__func__, rc);
rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
prtd->lsm_client->multi_snd_model_confidence_levels,
LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS);
if (rc)
dev_err(rtd->dev,
"%s: Failed to set multi_snd_model_confidence_levels, err = %d\n",
__func__, rc);
if (prtd->lsm_client->confidence_levels) {
kfree(prtd->lsm_client->confidence_levels);
prtd->lsm_client->confidence_levels = NULL;
if (prtd->lsm_client->multi_snd_model_confidence_levels) {
kfree(prtd->lsm_client->multi_snd_model_confidence_levels);
prtd->lsm_client->multi_snd_model_confidence_levels = NULL;
}
} else {
if (p_info->param_size > MAX_NUM_CONFIDENCE) {
dev_err(rtd->dev,
"%s: invalid confidence levels %d\n",
__func__, p_info->param_size);
return -EINVAL;
}
prtd->lsm_client->num_confidence_levels =
p_info->param_size;
rc = msm_lsm_get_conf_levels(prtd->lsm_client,
p_info->param_data);
if (rc) {
dev_err(rtd->dev,
"%s: get_conf_levels failed, err = %d\n",
__func__, rc);
return rc;
}
rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
prtd->lsm_client->confidence_levels,
LSM_MIN_CONFIDENCE_LEVELS);
if (rc)
dev_err(rtd->dev,
"%s: Failed to set min_conf_levels, err = %d\n",
__func__, rc);
if (prtd->lsm_client->confidence_levels) {
kfree(prtd->lsm_client->confidence_levels);
prtd->lsm_client->confidence_levels = NULL;
}
}
return rc;
}
@ -691,66 +756,166 @@ static int msm_lsm_reg_model(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
struct lsm_priv *prtd = runtime->private_data;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
int rc = 0;
int rc = 0, stage_idx = p_info->stage_idx;
struct lsm_sound_model *sm = NULL;
size_t offset = sizeof(union param_hdrs);
struct lsm_client *client = prtd->lsm_client;
rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client,
p_info->param_size, p_info);
if (rc) {
if (p_info->model_id != 0 &&
p_info->param_type == LSM_REG_MULTI_SND_MODEL) {
sm = kzalloc(sizeof(*sm), GFP_KERNEL);
if (sm == NULL) {
dev_err(rtd->dev, "%s: snd_model kzalloc failed\n", __func__);
return -ENOMEM;
}
INIT_LIST_HEAD(&sm->list);
rc = q6lsm_snd_model_buf_alloc(client, p_info->param_size, p_info, sm);
if (rc) {
dev_err(rtd->dev, "%s: snd_model buf alloc failed, size = %d\n",
__func__, p_info->param_size);
goto err_buf_alloc;
}
q6lsm_sm_set_param_data(client, p_info, &offset, sm);
/*
* For set_param, advance the sound model data with the
* number of bytes required by param_data.
*/
if (copy_from_user((u8 *)sm->data + offset,
p_info->param_data, p_info->param_size)) {
dev_err(rtd->dev,
"%s: copy_from_user for snd_model %d failed, size = %d\n",
__func__, p_info->model_id, p_info->param_size);
rc = -EFAULT;
goto err_copy;
}
/* Add this sound model to the list of multi sound models */
list_add_tail(&sm->list, &client->stage_cfg[stage_idx].sound_models);
rc = q6lsm_set_one_param(client, p_info, NULL,
LSM_REG_MULTI_SND_MODEL);
if (rc) {
dev_err(rtd->dev,
"%s: Failed to register snd_model %d, err = %d\n",
__func__, p_info->model_id, rc);
goto err_copy;
}
client->num_sound_models++;
dev_dbg(rtd->dev,
"%s: registered snd_model: %d, total num of snd_model: %d\n",
__func__, p_info->model_id, client->num_sound_models);
} else if (p_info->model_id == 0 &&
p_info->param_type == LSM_REG_SND_MODEL) {
sm = &client->stage_cfg[stage_idx].sound_model;
rc = q6lsm_snd_model_buf_alloc(client, p_info->param_size, p_info, sm);
if (rc) {
dev_err(rtd->dev, "%s: snd_model buf alloc failed, size = %d\n",
__func__, p_info->param_size);
return rc;
}
q6lsm_sm_set_param_data(client, p_info, &offset, sm);
/*
* For set_param, advance the sound model data with the
* number of bytes required by param_data.
*/
if (copy_from_user((u8 *)sm->data + offset,
p_info->param_data, p_info->param_size)) {
dev_err(rtd->dev,
"%s: copy_from_user for snd_model failed, size = %d\n",
__func__, p_info->param_size);
rc = -EFAULT;
goto err_copy;
}
rc = q6lsm_set_one_param(client, p_info, NULL, LSM_REG_SND_MODEL);
if (rc) {
dev_err(rtd->dev, "%s: Failed to register snd_model, err = %d\n",
__func__, rc);
goto err_copy;
}
} else {
dev_err(rtd->dev,
"%s: snd_model buf alloc failed, size = %d\n",
__func__, p_info->param_size);
return rc;
}
q6lsm_sm_set_param_data(prtd->lsm_client, p_info, &offset);
/*
* For set_param, advance the sound model data with the
* number of bytes required by param_data.
*/
sm = &prtd->lsm_client->stage_cfg[p_info->stage_idx].sound_model;
if (copy_from_user((u8 *)sm->data + offset,
p_info->param_data, p_info->param_size)) {
dev_err(rtd->dev,
"%s: copy_from_user for snd_model failed, size = %d\n",
__func__, p_info->param_size);
rc = -EFAULT;
goto err_copy;
}
rc = q6lsm_set_one_param(prtd->lsm_client, p_info, NULL,
LSM_REG_SND_MODEL);
if (rc) {
dev_err(rtd->dev,
"%s: Failed to set sound_model, err = %d\n",
__func__, rc);
goto err_copy;
"%s: snd_model id %d is invalid for param type %d\n",
__func__, p_info->model_id, p_info->param_type);
}
return rc;
err_copy:
q6lsm_snd_model_buf_free(prtd->lsm_client, p_info);
q6lsm_snd_model_buf_free(client, p_info, sm);
err_buf_alloc:
if (p_info->model_id != 0) {
list_del(&sm->list);
kfree(sm);
sm = NULL;
}
return rc;
}
static int msm_lsm_dereg_model(struct snd_pcm_substream *substream,
struct lsm_params_info_v2 *p_info)
struct lsm_params_info_v2 *p_info)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct lsm_priv *prtd = runtime->private_data;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct lsm_sound_model *sm = NULL;
struct lsm_client *client = prtd->lsm_client;
int rc = 0;
rc = q6lsm_set_one_param(prtd->lsm_client, p_info,
NULL, LSM_DEREG_SND_MODEL);
if (rc)
dev_err(rtd->dev,
"%s: Failed to set det_mode param, err = %d\n",
__func__, rc);
if (p_info->model_id != 0 &&
p_info->param_type == LSM_DEREG_MULTI_SND_MODEL) {
list_for_each_entry(sm,
&client->stage_cfg[p_info->stage_idx].sound_models,
list) {
dev_dbg(rtd->dev,
"%s: current snd_model: %d, looking for snd_model %d\n",
__func__, sm->model_id, p_info->model_id);
if (sm->model_id == p_info->model_id)
break;
}
q6lsm_snd_model_buf_free(prtd->lsm_client, p_info);
if (sm->model_id == p_info->model_id) {
rc = q6lsm_set_one_param(client, p_info, NULL,
LSM_DEREG_MULTI_SND_MODEL);
if (rc)
dev_err(rtd->dev,
"%s: Failed to deregister snd_model %d, err = %d\n",
__func__, p_info->model_id, rc);
q6lsm_snd_model_buf_free(client, p_info, sm);
list_del(&sm->list);
kfree(sm);
sm = NULL;
client->num_sound_models--;
} else {
rc = -EINVAL;
dev_err(rtd->dev,
"%s: Failed to find snd_model, invalid model_id %d\n",
__func__, p_info->model_id);
}
} else if (p_info->model_id == 0 &&
p_info->param_type == LSM_DEREG_SND_MODEL) {
rc = q6lsm_set_one_param(client, p_info, NULL,
LSM_DEREG_SND_MODEL);
if (rc)
dev_err(rtd->dev,
"%s: Failed to deregister snd_model, err = %d\n",
__func__, rc);
sm = &client->stage_cfg[p_info->stage_idx].sound_model;
q6lsm_snd_model_buf_free(client, p_info, sm);
} else {
rc = -EINVAL;
dev_err(rtd->dev,
"%s: snd_model id %d is invalid for param type %d\n",
__func__, p_info->model_id, p_info->param_type);
}
return rc;
}
@ -992,6 +1157,22 @@ static int msm_lsm_process_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
if (p_info->param_type == LSM_REG_MULTI_SND_MODEL &&
prtd->lsm_client->num_sound_models == LSM_MAX_SOUND_MODELS_SUPPORTED) {
dev_err(rtd->dev,
"%s: maximum supported sound models(8) have already reached\n",
__func__);
return -EINVAL;
}
if (p_info->param_type == LSM_DEREG_MULTI_SND_MODEL &&
prtd->lsm_client->num_sound_models == 0) {
dev_err(rtd->dev,
"%s: no available sound model to be deregistered\n",
__func__);
return -EINVAL;
}
switch (p_info->param_type) {
case LSM_ENDPOINT_DETECT_THRESHOLD:
rc = msm_lsm_set_epd(substream, p_info);
@ -1003,12 +1184,15 @@ static int msm_lsm_process_params(struct snd_pcm_substream *substream,
rc = msm_lsm_set_gain(substream, p_info);
break;
case LSM_MIN_CONFIDENCE_LEVELS:
case LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS:
rc = msm_lsm_set_conf(substream, p_info);
break;
case LSM_REG_SND_MODEL:
case LSM_REG_MULTI_SND_MODEL:
rc = msm_lsm_reg_model(substream, p_info);
break;
case LSM_DEREG_SND_MODEL:
case LSM_DEREG_MULTI_SND_MODEL:
rc = msm_lsm_dereg_model(substream, p_info);
break;
case LSM_CUSTOM_PARAMS:
@ -1176,7 +1360,10 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
* also set stage index to LSM_STAGE_INDEX_FIRST.
*/
struct lsm_params_info_v2 p_info = {0};
struct lsm_sound_model *sm = NULL;
p_info.stage_idx = LSM_STAGE_INDEX_FIRST;
p_info.param_type = LSM_DEREG_SND_MODEL;
sm = &prtd->lsm_client->stage_cfg[p_info.stage_idx].sound_model;
dev_dbg(rtd->dev, "%s: Registering sound model V2\n",
__func__);
@ -1192,21 +1379,20 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
break;
}
rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client,
snd_model_v2.data_size, &p_info);
snd_model_v2.data_size, &p_info, sm);
if (rc) {
dev_err(rtd->dev,
"%s: q6lsm buffer alloc failed V2, size %d\n",
__func__, snd_model_v2.data_size);
break;
}
if (copy_from_user(
prtd->lsm_client->stage_cfg[p_info.stage_idx].sound_model.data,
snd_model_v2.data, snd_model_v2.data_size)) {
if (copy_from_user(sm->data, snd_model_v2.data,
snd_model_v2.data_size)) {
dev_err(rtd->dev,
"%s: copy from user data failed\n"
"data %pK size %d\n", __func__,
snd_model_v2.data, snd_model_v2.data_size);
q6lsm_snd_model_buf_free(prtd->lsm_client, &p_info);
q6lsm_snd_model_buf_free(prtd->lsm_client, &p_info, sm);
rc = -EFAULT;
break;
}
@ -1234,7 +1420,7 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
dev_err(rtd->dev,
"%s: Register snd Model v2 failed =%d\n",
__func__, rc);
q6lsm_snd_model_buf_free(prtd->lsm_client, &p_info);
q6lsm_snd_model_buf_free(prtd->lsm_client, &p_info, sm);
}
if (prtd->lsm_client->confidence_levels) {
kfree(prtd->lsm_client->confidence_levels);
@ -1697,6 +1883,7 @@ struct lsm_params_info_v2_32 {
uint32_t param_type;
u16 instance_id;
u16 stage_idx;
u32 model_id;
};
struct snd_lsm_module_params_32 {
@ -2033,9 +2220,9 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
if (p_data.data_size != expected_size) {
dev_err(rtd->dev,
"%s: %s: Invalid size %d\n",
"%s: %s: Invalid size %d, expected_size %d\n",
__func__, "SET_MODULE_PARAMS(_V2)_32",
p_data.data_size);
p_data.data_size, expected_size);
err = -EINVAL;
goto done;
}
@ -2071,6 +2258,7 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
p_info.instance_id = INSTANCE_ID_0;
p_info.stage_idx = LSM_STAGE_INDEX_FIRST;
p_info.model_id = 0;
p_info_32++;
} else {
@ -2082,6 +2270,14 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
p_info.instance_id = p_info_v2_32->instance_id;
p_info.stage_idx = p_info_v2_32->stage_idx;
/* set sound model id to 0 for backward compatibility */
p_info.model_id = 0;
if (LSM_REG_MULTI_SND_MODEL == p_info_v2_32->param_type ||
LSM_DEREG_MULTI_SND_MODEL == p_info_v2_32->param_type ||
LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS ==
p_info_v2_32->param_type)
p_info.model_id = p_info_v2_32->model_id;
p_info_v2_32++;
}
@ -2208,7 +2404,6 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
case SNDRV_LSM_SET_MODULE_PARAMS_V2: {
struct snd_lsm_module_params p_data;
struct lsm_params_info *temp_ptr_info = NULL;
struct lsm_params_info_v2 info_v2;
struct lsm_params_info_v2 *ptr_info_v2 = NULL, *temp_ptr_info_v2 = NULL;
size_t p_size = 0, count;
u8 *params;
@ -2277,26 +2472,37 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
for (count = 0; count < p_data.num_params; count++) {
if (cmd == SNDRV_LSM_SET_MODULE_PARAMS) {
/* convert to V2 param info struct from legacy param info */
info_v2.module_id = temp_ptr_info->module_id;
info_v2.param_id = temp_ptr_info->param_id;
info_v2.param_size = temp_ptr_info->param_size;
info_v2.param_data = temp_ptr_info->param_data;
info_v2.param_type = temp_ptr_info->param_type;
ptr_info_v2->module_id = temp_ptr_info->module_id;
ptr_info_v2->param_id = temp_ptr_info->param_id;
ptr_info_v2->param_size = temp_ptr_info->param_size;
ptr_info_v2->param_data = temp_ptr_info->param_data;
ptr_info_v2->param_type = temp_ptr_info->param_type;
info_v2.instance_id = INSTANCE_ID_0;
info_v2.stage_idx = LSM_STAGE_INDEX_FIRST;
ptr_info_v2->instance_id = INSTANCE_ID_0;
ptr_info_v2->stage_idx = LSM_STAGE_INDEX_FIRST;
ptr_info_v2->model_id = 0;
ptr_info_v2 = &info_v2;
temp_ptr_info++;
} else {
/* Just copy the pointer as user already provided v2 params */
if (LSM_REG_MULTI_SND_MODEL != temp_ptr_info_v2->param_type ||
LSM_DEREG_MULTI_SND_MODEL !=
temp_ptr_info_v2->param_type ||
LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS !=
temp_ptr_info_v2->param_type) {
/* set sound model id to 0 for backward compatibility */
temp_ptr_info_v2->model_id = 0;
}
/*
* Just copy the pointer as user
* already provided sound model id
*/
ptr_info_v2 = temp_ptr_info_v2;
temp_ptr_info_v2++;
}
err = msm_lsm_process_params(substream, ptr_info_v2);
if (err)
dev_err(rtd->dev,
"%s: Failed to process param, type%d stage=%d err=%d\n",
"%s: Failed to process param, type=%d stage=%d err=%d\n",
__func__, ptr_info_v2->param_type,
ptr_info_v2->stage_idx, err);
}
@ -2464,7 +2670,7 @@ static int msm_lsm_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct lsm_priv *prtd;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
int ret = 0;
int ret = 0, i;
pr_debug("%s\n", __func__);
prtd = kzalloc(sizeof(struct lsm_priv), GFP_KERNEL);
@ -2530,6 +2736,12 @@ static int msm_lsm_open(struct snd_pcm_substream *substream)
prtd->lsm_client->event_type = LSM_DET_EVENT_TYPE_LEGACY;
prtd->lsm_client->fe_id = rtd->dai_link->id;
prtd->lsm_client->unprocessed_data = 0;
prtd->lsm_client->num_sound_models = 0;
prtd->lsm_client->num_keywords = 0;
prtd->lsm_client->multi_snd_model_confidence_levels = NULL;
for (i = 0; i < LSM_MAX_STAGES_PER_SESSION; i++)
INIT_LIST_HEAD(&prtd->lsm_client->stage_cfg[i].sound_models);
prtd->ws = wakeup_source_register(rtd->dev, "lsm-client");

View file

@ -908,17 +908,15 @@ done:
* @client: LSM client handle
* @p_info: param info
* @offset: pointer to retrieve size
*
* @sm: pointer to sound model
*/
void q6lsm_sm_set_param_data(struct lsm_client *client,
struct lsm_params_info_v2 *p_info,
size_t *offset)
struct lsm_params_info_v2 *p_info,
size_t *offset, struct lsm_sound_model *sm)
{
struct param_hdr_v3 param_hdr;
int ret;
struct lsm_sound_model *sm;
sm = &client->stage_cfg[p_info->stage_idx].sound_model;
memset(&param_hdr, 0, sizeof(param_hdr));
param_hdr.module_id = p_info->module_id;
@ -926,6 +924,8 @@ void q6lsm_sm_set_param_data(struct lsm_client *client,
param_hdr.param_id = p_info->param_id;
param_hdr.param_size = p_info->param_size;
sm->model_id = p_info->model_id;
ret = q6lsm_pack_params(sm->data, &param_hdr,
NULL, offset, LSM_SESSION_CMD_SET_PARAMS_V2);
if (ret)
@ -1010,42 +1010,78 @@ EXPORT_SYMBOL(q6lsm_open);
static int q6lsm_send_confidence_levels(struct lsm_client *client,
struct param_hdr_v3 *param_info,
uint32_t set_param_opcode)
uint32_t set_param_opcode, uint32_t model_id)
{
struct lsm_param_confidence_levels *conf_levels = NULL;
uint32_t num_conf_levels = client->num_confidence_levels;
struct lsm_param_multi_snd_model_conf_levels *multi_sm_conf_levels = NULL;
uint32_t num_keywords = client->num_keywords;
uint8_t i = 0;
uint8_t padd_size = 0;
uint32_t param_size = 0;
int rc = 0;
/* Data must be 4 byte aligned so add any necessary padding. */
padd_size = (4 - (num_conf_levels % 4)) - 1;
param_size = (sizeof(uint8_t) + num_conf_levels + padd_size) *
sizeof(uint8_t);
param_info->param_size = param_size;
pr_debug("%s: Set Conf Levels PARAM SIZE = %d\n", __func__, param_size);
if (model_id != 0) {
/* No padding is need since the structure is always 4 byte aligend.
* The number "2" below represents the first two u32 variables in
* struct lsm_param_multi_snd_model_conf_levels.
*/
param_size = (2 + num_keywords) * sizeof(uint32_t);
param_info->param_size = param_size;
pr_debug("%s: Set Conf Levels PARAM SIZE: %d\n", __func__, param_size);
conf_levels = kzalloc(param_size, GFP_KERNEL);
if (!conf_levels)
return -ENOMEM;
multi_sm_conf_levels = kzalloc(param_size, GFP_KERNEL);
if (!multi_sm_conf_levels)
return -ENOMEM;
conf_levels->num_confidence_levels = num_conf_levels;
pr_debug("%s: Num conf_level = %d\n", __func__, num_conf_levels);
multi_sm_conf_levels->model_id = model_id;
multi_sm_conf_levels->num_keywords = num_keywords;
pr_debug("%s: snd_model id: %d, num_keywords: %d\n",
__func__, model_id, num_keywords);
memcpy(conf_levels->confidence_levels, client->confidence_levels,
num_conf_levels);
for (i = 0; i < num_conf_levels; i++)
pr_debug("%s: Confidence_level[%d] = %d\n", __func__, i,
conf_levels->confidence_levels[i]);
memcpy(multi_sm_conf_levels->confidence_levels,
client->multi_snd_model_confidence_levels,
sizeof(uint32_t) * num_keywords);
for (i = 0; i < num_keywords; i++)
pr_debug("%s: Confidence_level[%d] = %d\n", __func__, i,
multi_sm_conf_levels->confidence_levels[i]);
rc = q6lsm_pack_and_set_params(client, param_info,
(uint8_t *) conf_levels,
set_param_opcode);
if (rc)
pr_err("%s: Send confidence_levels cmd failed, err = %d\n",
__func__, rc);
kfree(conf_levels);
rc = q6lsm_pack_and_set_params(client, param_info,
(uint8_t *) multi_sm_conf_levels,
set_param_opcode);
if (rc)
pr_err("%s: Send multi_snd_model_conf_levels cmd failed, err %d\n",
__func__, rc);
kfree(multi_sm_conf_levels);
} else {
/* Data must be 4 byte aligned so add any necessary padding. */
padd_size = (4 - (num_conf_levels % 4)) - 1;
param_size = (sizeof(uint8_t) + num_conf_levels + padd_size) *
sizeof(uint8_t);
param_info->param_size = param_size;
pr_debug("%s: Set Conf Levels PARAM SIZE = %d\n", __func__, param_size);
conf_levels = kzalloc(param_size, GFP_KERNEL);
if (!conf_levels)
return -ENOMEM;
conf_levels->num_confidence_levels = num_conf_levels;
pr_debug("%s: Num conf_level = %d\n", __func__, num_conf_levels);
memcpy(conf_levels->confidence_levels, client->confidence_levels,
num_conf_levels);
for (i = 0; i < num_conf_levels; i++)
pr_debug("%s: Confidence_level[%d] = %d\n", __func__, i,
conf_levels->confidence_levels[i]);
rc = q6lsm_pack_and_set_params(client, param_info,
(uint8_t *) conf_levels,
set_param_opcode);
if (rc)
pr_err("%s: Send confidence_levels cmd failed, err = %d\n",
__func__, rc);
kfree(conf_levels);
}
return rc;
}
@ -1459,7 +1495,7 @@ int q6lsm_set_data(struct lsm_client *client,
param_hdr.param_id = LSM_PARAM_ID_MIN_CONFIDENCE_LEVELS;
rc = q6lsm_send_confidence_levels(client, &param_hdr,
LSM_SESSION_CMD_SET_PARAMS);
LSM_SESSION_CMD_SET_PARAMS, 0);
if (rc) {
pr_err("%s: Failed to send conf_levels, err = %d\n",
__func__, rc);
@ -1537,8 +1573,9 @@ EXPORT_SYMBOL(q6lsm_register_sound_model);
*/
int q6lsm_deregister_sound_model(struct lsm_client *client)
{
int rc;
int rc = 0;
struct lsm_cmd_reg_snd_model cmd;
struct lsm_sound_model *sm = NULL, *next = NULL;
/*
* With multi-stage support sm buff allocation/free usage param info
* to check stage index for which this sound model is being set, and
@ -1564,19 +1601,39 @@ int q6lsm_deregister_sound_model(struct lsm_client *client)
return -EINVAL;
}
memset(&cmd, 0, sizeof(cmd));
q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd.hdr), false);
cmd.hdr.opcode = LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL;
if (client->num_sound_models > 0) {
p_info.param_type = LSM_DEREG_MULTI_SND_MODEL;
list_for_each_entry_safe(sm, next,
&client->stage_cfg[p_info.stage_idx].sound_models,
list) {
pr_debug("%s: current snd_model: %d, num of sound models left %d\n",
__func__, sm->model_id, client->num_sound_models);
q6lsm_snd_model_buf_free(client, &p_info, sm);
list_del(&sm->list);
kfree(sm);
sm = NULL;
client->num_sound_models--;
rc = q6lsm_apr_send_pkt(client, client->apr, &cmd.hdr, true, NULL);
if (rc) {
pr_err("%s: Failed cmd opcode 0x%x, rc %d\n", __func__,
cmd.hdr.opcode, rc);
if (0 == client->num_sound_models)
break;
}
} else {
pr_debug("%s: Deregister sound model succeeded\n", __func__);
}
memset(&cmd, 0, sizeof(cmd));
q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd.hdr), false);
cmd.hdr.opcode = LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL;
q6lsm_snd_model_buf_free(client, &p_info);
rc = q6lsm_apr_send_pkt(client, client->apr, &cmd.hdr, true, NULL);
if (rc) {
pr_err("%s: Failed cmd opcode 0x%x, rc %d\n", __func__,
cmd.hdr.opcode, rc);
} else {
pr_debug("%s: Deregister sound model succeeded\n", __func__);
}
p_info.param_type = LSM_DEREG_SND_MODEL;
sm = &client->stage_cfg[p_info.stage_idx].sound_model;
q6lsm_snd_model_buf_free(client, &p_info, sm);
}
return rc;
}
@ -1825,14 +1882,15 @@ fail:
*
* @client: LSM client handle
* @p_info: sound model param info
* @sm: pointer to sound model
*
* Returns 0 on success or error on failure
*/
int q6lsm_snd_model_buf_free(struct lsm_client *client,
struct lsm_params_info_v2 *p_info)
struct lsm_params_info_v2 *p_info,
struct lsm_sound_model *sm)
{
int rc = 0, stage_idx = p_info->stage_idx;
struct lsm_sound_model *sm = NULL;
pr_debug("%s: Session id %d\n", __func__, client->session);
if (CHECK_SESSION(client->session)) {
@ -1840,11 +1898,11 @@ int q6lsm_snd_model_buf_free(struct lsm_client *client,
return -EINVAL;
}
if (!client->stage_cfg[stage_idx].sound_model.data)
if (p_info->param_type == LSM_DEREG_SND_MODEL &&
!client->stage_cfg[stage_idx].sound_model.data)
return 0;
mutex_lock(&client->cmd_lock);
sm = &client->stage_cfg[stage_idx].sound_model;
if (sm->mem_map_handle != 0) {
rc = q6lsm_memory_unmap_regions(client, sm->mem_map_handle);
if (rc)
@ -1858,7 +1916,10 @@ int q6lsm_snd_model_buf_free(struct lsm_client *client,
sm->phys = 0;
mutex_unlock(&client->cmd_lock);
rc = q6lsm_snd_cal_free(client, p_info);
if ((p_info->param_type == LSM_DEREG_MULTI_SND_MODEL &&
client->num_sound_models == 1) ||
p_info->param_type == LSM_DEREG_SND_MODEL)
rc = q6lsm_snd_cal_free(client, p_info);
return rc;
}
EXPORT_SYMBOL(q6lsm_snd_model_buf_free);
@ -1980,20 +2041,20 @@ static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv)
* Returns 0 on success or error on failure
*/
int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
struct lsm_params_info_v2 *p_info)
struct lsm_params_info_v2 *p_info,
struct lsm_sound_model *sm)
{
int rc = -EINVAL, stage_idx = p_info->stage_idx;
int model_id = p_info->model_id;
size_t total_mem = 0;
struct lsm_sound_model *sm = NULL;
if (!client)
return rc;
pr_debug("%s:Snd Model len = %zd, stage idx %d\n",
__func__, len, stage_idx);
pr_debug("%s:Snd Model len %zd, stage_idx %d, model_id %d\n",
__func__, len, stage_idx, model_id);
mutex_lock(&client->cmd_lock);
sm = &client->stage_cfg[stage_idx].sound_model;
if (!sm->data) {
/*
* If sound model is sent as set_param, i.e. param_id != 0,
@ -2008,7 +2069,7 @@ int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
pr_debug("%s: sm param size %zd Total mem %zd, stage_idx %d\n",
__func__, len, total_mem, stage_idx);
rc = msm_audio_ion_alloc(&sm->dma_buf, total_mem,
&sm->phys, &len, &sm->data);
&sm->phys, &len, &sm->data);
if (rc) {
pr_err("%s: Audio ION alloc is failed, rc = %d, stage_idx = %d\n",
__func__, rc, stage_idx);
@ -2040,7 +2101,7 @@ int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
fail:
mutex_unlock(&client->cmd_lock);
fail_1:
q6lsm_snd_model_buf_free(client, p_info);
q6lsm_snd_model_buf_free(client, p_info, sm);
return rc;
}
EXPORT_SYMBOL(q6lsm_snd_model_buf_alloc);
@ -2126,8 +2187,8 @@ static int q6lsm_send_param_gain(struct lsm_client *client, u16 gain,
* Returns 0 on success or error on failure
*/
int q6lsm_set_one_param(struct lsm_client *client,
struct lsm_params_info_v2 *p_info, void *data,
uint32_t param_type)
struct lsm_params_info_v2 *p_info,
void *data, uint32_t param_type)
{
struct param_hdr_v3 param_info;
int rc = 0;
@ -2186,14 +2247,19 @@ int q6lsm_set_one_param(struct lsm_client *client,
}
case LSM_MIN_CONFIDENCE_LEVELS:
case LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS:
param_info.module_id = p_info->module_id;
param_info.instance_id = p_info->instance_id;
param_info.param_id = p_info->param_id;
rc = q6lsm_send_confidence_levels(
client, &param_info, LSM_SESSION_CMD_SET_PARAMS_V2);
client, &param_info, LSM_SESSION_CMD_SET_PARAMS_V2,
p_info->model_id);
if (rc)
pr_err("%s: CONFIDENCE_LEVELS cmd failed, rc %d\n",
__func__, rc);
pr_err("%s: %s cmd failed, rc %d\n",
__func__,
param_type == LSM_MIN_CONFIDENCE_LEVELS ?
"LSM_MIN_CONFIDENCE_LEVELS" :
"LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS", rc);
break;
case LSM_POLLING_ENABLE: {
struct snd_lsm_poll_enable *lsm_poll_enable =
@ -2210,7 +2276,8 @@ int q6lsm_set_one_param(struct lsm_client *client,
break;
}
case LSM_REG_SND_MODEL: {
case LSM_REG_SND_MODEL:
case LSM_REG_MULTI_SND_MODEL: {
struct mem_mapping_hdr mem_hdr;
u32 payload_size;
struct lsm_sound_model *sm = NULL;
@ -2224,8 +2291,18 @@ int q6lsm_set_one_param(struct lsm_client *client,
payload_size = p_info->param_size +
sizeof(struct param_hdr_v2);
sm = &client->stage_cfg[p_info->stage_idx].sound_model;
if (param_type == LSM_REG_MULTI_SND_MODEL) {
list_for_each_entry(sm,
&client->stage_cfg[p_info->stage_idx].sound_models,
list) {
pr_debug("%s: current snd_model: %d, looking for snd_model %d\n",
__func__, sm->model_id, p_info->model_id);
if (sm->model_id == p_info->model_id)
break;
}
} else {
sm = &client->stage_cfg[p_info->stage_idx].sound_model;
}
mem_hdr.data_payload_addr_lsw =
lower_32_bits(sm->phys);
mem_hdr.data_payload_addr_msw =
@ -2236,28 +2313,41 @@ int q6lsm_set_one_param(struct lsm_client *client,
rc = q6lsm_set_params(client, &mem_hdr, NULL, payload_size,
LSM_SESSION_CMD_SET_PARAMS_V2);
if (rc) {
pr_err("%s: REG_SND_MODEL failed, rc %d\n",
__func__, rc);
pr_err("%s: %s failed, rc %d\n",
__func__, param_type == LSM_REG_SND_MODEL ?
"LSM_REG_SND_MODEL" : "LSM_REG_MULTI_SND_MODEL", rc);
return rc;
}
rc = q6lsm_send_cal(client, LSM_SESSION_CMD_SET_PARAMS, p_info);
if (rc)
pr_err("%s: Failed to send lsm cal, err = %d\n",
__func__, rc);
if (client->num_sound_models == 0) {
rc = q6lsm_send_cal(client, LSM_SESSION_CMD_SET_PARAMS, p_info);
if (rc)
pr_err("%s: Failed to send lsm cal, err = %d\n",
__func__, rc);
}
break;
}
case LSM_DEREG_SND_MODEL: {
case LSM_DEREG_SND_MODEL:
case LSM_DEREG_MULTI_SND_MODEL: {
param_info.module_id = p_info->module_id;
param_info.instance_id = p_info->instance_id;
param_info.param_id = p_info->param_id;
param_info.param_size = 0;
rc = q6lsm_pack_and_set_params(client, &param_info, NULL,
LSM_SESSION_CMD_SET_PARAMS_V2);
if (param_type == LSM_DEREG_MULTI_SND_MODEL) {
param_info.param_size = p_info->param_size;
rc = q6lsm_pack_and_set_params(client, &param_info,
(uint8_t *)&p_info->model_id,
LSM_SESSION_CMD_SET_PARAMS_V2);
} else {
rc = q6lsm_pack_and_set_params(client, &param_info, NULL,
LSM_SESSION_CMD_SET_PARAMS_V2);
}
if (rc)
pr_err("%s: DEREG_SND_MODEL failed, rc %d\n",
__func__, rc);
pr_err("%s: %s failed, rc %d\n",
__func__, param_type == LSM_DEREG_SND_MODEL ?
"LSM_DEREG_SND_MODEL" : "LSM_DEREG_MULTI_SND_MODEL", rc);
break;
}

View file

@ -22,6 +22,10 @@
#define MAX_LSM_SESSIONS 8
#define MAX_KEYWORDS_SUPPORTED 8
#define LSM_MAX_SOUND_MODELS_SUPPORTED 8
typedef void (*lsm_app_cb)(uint32_t opcode, uint32_t token,
uint32_t *payload, uint16_t client_size, void *priv);
@ -32,6 +36,8 @@ struct lsm_sound_model {
uint32_t actual_size; /* actual number of bytes read by DSP */
struct dma_buf *dma_buf;
uint32_t mem_map_handle;
uint32_t model_id;
struct list_head list;
};
struct snd_lsm_event_status_v2 {
@ -71,6 +77,7 @@ struct lsm_stage_config {
bool lab_enable;
struct lsm_sound_model sound_model;
struct lsm_cal_data_info cal_info;
struct list_head sound_models;
};
@ -106,6 +113,9 @@ struct lsm_client {
struct lsm_stage_config stage_cfg[LSM_MAX_STAGES_PER_SESSION];
uint64_t fe_id;
uint16_t unprocessed_data;
uint32_t num_sound_models;
uint32_t num_keywords;
uint32_t *multi_snd_model_confidence_levels;
};
struct lsm_stream_cmd_open_tx {
@ -193,6 +203,11 @@ struct lsm_param_media_fmt_v2 {
uint8_t channel_mapping[0];
} __packed;
struct lsm_param_multi_snd_model_conf_levels {
uint32_t model_id;
uint32_t num_keywords;
uint32_t confidence_levels[0];
} __packed;
struct lsm_param_confidence_levels {
uint8_t num_confidence_levels;
@ -268,9 +283,9 @@ int q6lsm_open(struct lsm_client *client, uint16_t app_id);
int q6lsm_start(struct lsm_client *client, bool wait);
int q6lsm_stop(struct lsm_client *client, bool wait);
int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
struct lsm_params_info_v2 *p_info);
struct lsm_params_info_v2 *p_info, struct lsm_sound_model *sm);
int q6lsm_snd_model_buf_free(struct lsm_client *client,
struct lsm_params_info_v2 *p_info);
struct lsm_params_info_v2 *p_info, struct lsm_sound_model *sm);
int q6lsm_close(struct lsm_client *client);
int q6lsm_register_sound_model(struct lsm_client *client,
enum lsm_detection_mode mode,
@ -290,8 +305,8 @@ int q6lsm_set_one_param(struct lsm_client *client,
struct lsm_params_info_v2 *p_info, void *data,
uint32_t param_type);
void q6lsm_sm_set_param_data(struct lsm_client *client,
struct lsm_params_info_v2 *p_info,
size_t *offset);
struct lsm_params_info_v2 *p_info, size_t *offset,
struct lsm_sound_model *sm);
int q6lsm_set_port_connected(struct lsm_client *client);
int q6lsm_set_fwk_mode_cfg(struct lsm_client *client, uint32_t event_mode);
int q6lsm_set_media_fmt_params(struct lsm_client *client);

View file

@ -6,7 +6,7 @@
#include <linux/types.h>
#define SNDRV_LSM_VERSION SNDRV_PROTOCOL_VERSION(0, 3, 1)
#define SNDRV_LSM_VERSION SNDRV_PROTOCOL_VERSION(0, 3, 2)
#define LSM_MAX_STAGES_PER_SESSION 2
#define LSM_STAGE_INDEX_FIRST 0
@ -33,7 +33,10 @@
#define LSM_POLLING_ENABLE (7)
#define LSM_DET_EVENT_TYPE (8)
#define LSM_LAB_CONTROL (9)
#define LSM_PARAMS_MAX (LSM_LAB_CONTROL + 1)
#define LSM_REG_MULTI_SND_MODEL (10)
#define LSM_DEREG_MULTI_SND_MODEL (11)
#define LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS (12)
#define LSM_PARAMS_MAX (LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS + 1)
#define LSM_EVENT_NON_TIME_STAMP_MODE (0)
#define LSM_EVENT_TIME_STAMP_MODE (1)
@ -226,6 +229,7 @@ struct lsm_params_info {
* Member variables applicable only to V2:
* @instance_id: instance id of the param to which parameter is to be set
* @stage_idx: detection stage for which the param is applicable
* @model_id: an unique number to identify sound models in DSP
*/
struct lsm_params_info_v2 {
__u32 module_id;
@ -235,6 +239,7 @@ struct lsm_params_info_v2 {
__u32 param_type;
__u16 instance_id;
__u16 stage_idx;
__u32 model_id;
};
/*