From 2fdf19ac8e37cdf4f1392a9de7cf6e9fb03cfa8b Mon Sep 17 00:00:00 2001 From: Harshal Ahire Date: Tue, 4 Aug 2020 13:17:51 +0530 Subject: [PATCH] dsp: Add support for GET_PARAMS Add support to query module parameters from ADSP. Change-Id: Ie63dd95cf27277f9c836becc98952d48971a3ec3 Signed-off-by: Harshal Ahire --- asoc/msm-lsm-client.c | 177 ++++++++++++++++++++++++++ dsp/q6lsm.c | 147 +++++++++++++++++++++ include/dsp/apr_audio-v2.h | 4 + include/dsp/q6lsm.h | 17 +++ include/uapi/audio/sound/lsm_params.h | 29 ++++- 5 files changed, 372 insertions(+), 2 deletions(-) diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c index be997b4a7470..ea62100354a2 100644 --- a/asoc/msm-lsm-client.c +++ b/asoc/msm-lsm-client.c @@ -1894,6 +1894,17 @@ struct lsm_params_info_v2_32 { u32 model_id; }; +struct lsm_params_get_info_32 { + u32 module_id; + u16 instance_id; + u16 reserved; + u32 param_id; + u32 param_size; + uint32_t param_type; + __u16 stage_idx; + u8 payload[0]; +} __packed; + struct snd_lsm_module_params_32 { compat_uptr_t params; u32 num_params; @@ -1911,6 +1922,8 @@ enum { _IOW('U', 0x0F, struct snd_lsm_event_status_v3_32), SNDRV_LSM_SET_MODULE_PARAMS_V2_32 = _IOW('U', 0x13, struct snd_lsm_module_params_32), + SNDRV_LSM_GET_MODULE_PARAMS_32 = + _IOWR('U', 0x14, struct lsm_params_get_info_32), }; #if IS_ENABLED(CONFIG_AUDIO_QGKI) @@ -2300,6 +2313,95 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream, kfree(params32); break; } + case SNDRV_LSM_GET_MODULE_PARAMS_32: { + struct lsm_params_get_info_32 p_info_32, *param_info_rsp = NULL; + struct lsm_params_get_info *p_info = NULL; + + memset(&p_info_32, 0 , sizeof(p_info_32)); + if (!prtd->lsm_client->use_topology) { + dev_err(rtd->dev, + "%s: %s: not supported if not using topology\n", + __func__, "GET_MODULE_PARAMS_32"); + err = -EINVAL; + goto done; + } + + if (copy_from_user(&p_info_32, arg, sizeof(p_info_32))) { + dev_err(rtd->dev, + "%s: %s: copy_from_user failed, size = %zd\n", + __func__, "GET_MODULE_PARAMS_32", + sizeof(p_info_32)); + err = -EFAULT; + goto done; + } + size = sizeof(p_info_32); + p_info = kzalloc(size, GFP_KERNEL); + + if (!p_info) { + err = -ENOMEM; + goto done; + } + + p_info->module_id = p_info_32.module_id; + p_info->param_id = p_info_32.param_id; + p_info->param_size = p_info_32.param_size; + p_info->param_type = p_info_32.param_type; + p_info->instance_id = p_info_32.instance_id; + p_info->stage_idx = p_info_32.stage_idx; + + prtd->lsm_client->get_param_payload = kzalloc(p_info_32.param_size, + GFP_KERNEL); + if (!prtd->lsm_client->get_param_payload) { + err = -ENOMEM; + kfree(p_info); + goto done; + } + prtd->lsm_client->param_size = p_info_32.param_size; + + err = q6lsm_get_one_param(prtd->lsm_client, p_info, + LSM_GET_CUSTOM_PARAMS); + if (err) { + dev_err(rtd->dev, + "%s: Failed to get custom param, err=%d\n", + __func__, err); + kfree(p_info); + kfree(prtd->lsm_client->get_param_payload); + goto done; + } + + size = sizeof(p_info_32) + p_info_32.param_size; + param_info_rsp = kzalloc(size, GFP_KERNEL); + + if (!param_info_rsp) { + err = -ENOMEM; + kfree(p_info); + kfree(prtd->lsm_client->get_param_payload); + goto done; + } + + if (!access_ok(arg, size)) { + dev_err(rtd->dev, + "%s: Failed to verify write, size = %d\n", + __func__, size); + err = -EFAULT; + goto free; + } + + memcpy(param_info_rsp, &p_info_32, sizeof(p_info_32)); + memcpy(param_info_rsp->payload, prtd->lsm_client->get_param_payload, + p_info_32.param_size); + + if (copy_to_user(arg, param_info_rsp, size)) { + dev_err(rtd->dev, "%s: Failed to copy payload to user, size = %d\n", + __func__, size); + err = -EFAULT; + } +free: + kfree(p_info); + kfree(param_info_rsp); + kfree(prtd->lsm_client->get_param_payload); + break; + } case SNDRV_LSM_REG_SND_MODEL_V2: case SNDRV_LSM_SET_PARAMS: case SNDRV_LSM_SET_MODULE_PARAMS: @@ -2522,6 +2624,81 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream, break; } + case SNDRV_LSM_GET_MODULE_PARAMS: { + struct lsm_params_get_info temp_p_info, *p_info = NULL; + + memset(&temp_p_info, 0, sizeof(temp_p_info)); + if (!prtd->lsm_client->use_topology) { + dev_err(rtd->dev, + "%s: %s: not supported if not using topology\n", + __func__, "GET_MODULE_PARAMS_32"); + err = -EINVAL; + goto done; + } + + if (copy_from_user(&temp_p_info, arg, sizeof(temp_p_info))) { + dev_err(rtd->dev, + "%s: %s: copy_from_user failed, size = %zd\n", + __func__, "GET_MODULE_PARAMS_32", + sizeof(temp_p_info)); + err = -EFAULT; + goto done; + } + size = sizeof(temp_p_info) + temp_p_info.param_size; + p_info = kzalloc(size, GFP_KERNEL); + + if (!p_info) { + err = -ENOMEM; + goto done; + } + + p_info->module_id = temp_p_info.module_id; + p_info->param_id = temp_p_info.param_id; + p_info->param_size = temp_p_info.param_size; + p_info->param_type = temp_p_info.param_type; + p_info->instance_id = temp_p_info.instance_id; + p_info->stage_idx = temp_p_info.stage_idx; + + prtd->lsm_client->get_param_payload = kzalloc(temp_p_info.param_size, + GFP_KERNEL); + if (!prtd->lsm_client->get_param_payload) { + err = -ENOMEM; + kfree(p_info); + goto done; + } + + prtd->lsm_client->param_size = p_info->param_size; + err = q6lsm_get_one_param(prtd->lsm_client, p_info, + LSM_GET_CUSTOM_PARAMS); + if (err) { + dev_err(rtd->dev, + "%s: Failed to get custom param, err=%d\n", + __func__, err); + goto free; + } + + if (!access_ok(arg, size)) { + dev_err(rtd->dev, + "%s: Failed to verify write, size = %d\n", + __func__, size); + err = -EFAULT; + goto free; + } + + memcpy(p_info->payload, prtd->lsm_client->get_param_payload, + temp_p_info.param_size); + + if (copy_to_user(arg, p_info, sizeof(struct lsm_params_get_info) + + p_info->param_size)) { + dev_err(rtd->dev, "%s: Failed to copy payload to user, size = %d\n", + __func__, size); + err = -EFAULT; + } +free: + kfree(p_info); + kfree(prtd->lsm_client->get_param_payload); + break; + } case SNDRV_LSM_EVENT_STATUS: case SNDRV_LSM_GENERIC_DET_EVENT: { struct snd_lsm_event_status *user = NULL; diff --git a/dsp/q6lsm.c b/dsp/q6lsm.c index b44a7f474f91..87b3f08f1ebd 100644 --- a/dsp/q6lsm.c +++ b/dsp/q6lsm.c @@ -190,6 +190,58 @@ static int q6lsm_callback(struct apr_client_data *data, void *priv) client->priv); spin_unlock_irqrestore(&lsm_session_lock, flags); return 0; + } else if (data->opcode == LSM_SESSION_CMDRSP_GET_PARAMS_V3 || + data->opcode == LSM_SESSION_CMDRSP_GET_PARAMS_V2) { + + uint32_t payload_min_size_expected = 0; + uint32_t param_size = 0, ret = 0; + /* + * sizeof(uint32_t) is added to accomodate the status field + * in adsp response payload + */ + + if (data->opcode == LSM_SESSION_CMDRSP_GET_PARAMS_V3) + payload_min_size_expected = sizeof(uint32_t) + + sizeof(struct param_hdr_v3); + else + payload_min_size_expected = sizeof(uint32_t) + + sizeof(struct param_hdr_v2); + + if (data->payload_size < payload_min_size_expected) { + pr_err("%s: invalid payload size %d expected size %d\n", + __func__, data->payload_size, + payload_min_size_expected); + ret = -EINVAL; + goto done; + } + + if (data->opcode == LSM_SESSION_CMDRSP_GET_PARAMS_V3) + param_size = payload[4]; + else + param_size = payload[3]; + + if (data->payload_size != payload_min_size_expected + param_size) { + pr_err("%s: cmdrsp_get_params error payload size %d expected size %d\n", + __func__, data->payload_size, + payload_min_size_expected + param_size); + ret = -EINVAL; + goto done; + } + + if (client->param_size != param_size) { + pr_err("%s: response payload size %d mismatched with user requested %d\n", + __func__, param_size, client->param_size); + ret = -EINVAL; + goto done; + } + + memcpy((u8 *)client->get_param_payload, + (u8 *)payload + payload_min_size_expected, param_size); +done: + spin_unlock_irqrestore(&lsm_session_lock, flags); + atomic_set(&client->cmd_state, CMD_STATE_CLEARED); + wake_up(&client->cmd_wait); + return ret; } else if (data->opcode == APR_BASIC_RSP_RESULT) { token = data->token; switch (payload[0]) { @@ -208,6 +260,8 @@ static int q6lsm_callback(struct apr_client_data *data, void *priv) case LSM_CMD_ADD_TOPOLOGIES: case LSM_SESSION_CMD_SET_PARAMS_V2: case LSM_SESSION_CMD_SET_PARAMS_V3: + case LSM_SESSION_CMD_GET_PARAMS_V2: + case LSM_SESSION_CMD_GET_PARAMS_V3: if (token != client->session && payload[0] != LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL) { @@ -623,6 +677,48 @@ done: return ret; } +static int q6lsm_get_params_v2(struct lsm_client *client, + struct mem_mapping_hdr *mem_hdr, + struct param_hdr_v2 *param_hdr) +{ + struct lsm_session_cmd_get_params_v2 lsm_get_param; + uint16_t pkt_size = sizeof(lsm_get_param); + + memset(&lsm_get_param, 0, pkt_size); + q6lsm_add_hdr(client, &lsm_get_param.apr_hdr, pkt_size, true); + lsm_get_param.apr_hdr.opcode = LSM_SESSION_CMD_GET_PARAMS_V2; + + if (mem_hdr != NULL) + lsm_get_param.mem_hdr = *mem_hdr; + + memcpy(&lsm_get_param.param_info, param_hdr, + sizeof(struct param_hdr_v2)); + + return q6lsm_apr_send_pkt(client, client->apr, &lsm_get_param, true, + NULL); +} + +static int q6lsm_get_params_v3(struct lsm_client *client, + struct mem_mapping_hdr *mem_hdr, + struct param_hdr_v3 *param_hdr) +{ + struct lsm_session_cmd_get_params_v3 lsm_get_param; + uint16_t pkt_size = sizeof(lsm_get_param); + + memset(&lsm_get_param, 0, pkt_size); + q6lsm_add_hdr(client, &lsm_get_param.apr_hdr, pkt_size, true); + lsm_get_param.apr_hdr.opcode = LSM_SESSION_CMD_GET_PARAMS_V3; + + if (mem_hdr != NULL) + lsm_get_param.mem_hdr = *mem_hdr; + + memcpy(&lsm_get_param.param_info, param_hdr, + sizeof(struct param_hdr_v3)); + + return q6lsm_apr_send_pkt(client, client->apr, &lsm_get_param, true, + NULL); +} + static int q6lsm_set_params(struct lsm_client *client, struct mem_mapping_hdr *mem_hdr, uint8_t *param_data, uint32_t param_size, @@ -665,6 +761,27 @@ done: return ret; } +static int q6lsm_get_params(struct lsm_client *client, + struct mem_mapping_hdr *mem_hdr, + struct param_hdr_v3 *param_info) + +{ + struct param_hdr_v2 param_info_v2; + int ret = 0; + bool iid_supported = q6common_is_instance_id_supported(); + memset(¶m_info_v2, 0, sizeof(struct param_hdr_v2)); + + if (iid_supported) + ret = q6lsm_get_params_v3(client, mem_hdr, param_info); + else { + param_info_v2.module_id = param_info->module_id; + param_info_v2.param_id = param_info->param_id; + param_info_v2.param_size = param_info->param_size; + ret = q6lsm_get_params_v2(client, mem_hdr, ¶m_info_v2); + } + return ret; +} + static int q6lsm_send_custom_topologies(struct lsm_client *client) { int rc; @@ -2403,6 +2520,36 @@ int q6lsm_set_one_param(struct lsm_client *client, } EXPORT_SYMBOL(q6lsm_set_one_param); +int q6lsm_get_one_param(struct lsm_client *client, + struct lsm_params_get_info *p_info, + uint32_t param_type) +{ + struct param_hdr_v3 param_info; + int rc = 0; + + memset(¶m_info, 0, sizeof(param_info)); + + switch (param_type) { + case LSM_GET_CUSTOM_PARAMS: { + 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 = p_info->param_size + sizeof(param_info); + rc = q6lsm_get_params(client, NULL, ¶m_info); + if (rc) { + pr_err("%s: LSM_GET_CUSTOM_PARAMS failed, rc %d\n", + __func__, rc); + } + break; + + } + default: + pr_err("%s: wrong param_type 0x%x\n", + __func__, p_info->param_type); + } + return rc; +} +EXPORT_SYMBOL(q6lsm_get_one_param); /** * q6lsm_start - diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h index 090bceb4d5f9..387ebfdf80d4 100644 --- a/include/dsp/apr_audio-v2.h +++ b/include/dsp/apr_audio-v2.h @@ -11717,6 +11717,10 @@ struct avcs_fwk_ver_info { #define LSM_SESSION_CMD_SET_PARAMS (0x00012A83) #define LSM_SESSION_CMD_SET_PARAMS_V2 (0x00012A8F) #define LSM_SESSION_CMD_SET_PARAMS_V3 (0x00012A92) +#define LSM_SESSION_CMD_GET_PARAMS_V2 (0x00012A90) +#define LSM_SESSION_CMDRSP_GET_PARAMS_V2 (0x00012A91) +#define LSM_SESSION_CMD_GET_PARAMS_V3 (0x00012A93) +#define LSM_SESSION_CMDRSP_GET_PARAMS_V3 (0x00012A94) #define LSM_SESSION_CMD_REGISTER_SOUND_MODEL (0x00012A84) #define LSM_SESSION_CMD_DEREGISTER_SOUND_MODEL (0x00012A85) #define LSM_SESSION_CMD_START (0x00012A86) diff --git a/include/dsp/q6lsm.h b/include/dsp/q6lsm.h index e4431bc9127d..03915ecaa330 100644 --- a/include/dsp/q6lsm.h +++ b/include/dsp/q6lsm.h @@ -116,6 +116,8 @@ struct lsm_client { uint32_t num_sound_models; uint32_t num_keywords; uint32_t *multi_snd_model_confidence_levels; + void *get_param_payload; + size_t param_size; }; struct lsm_stream_cmd_open_tx { @@ -163,6 +165,18 @@ struct lsm_session_cmd_set_params_v3 { u32 param_data[0]; } __packed; +struct lsm_session_cmd_get_params_v2 { + struct apr_hdr apr_hdr; + struct mem_mapping_hdr mem_hdr; + struct param_hdr_v2 param_info; +} __packed; + +struct lsm_session_cmd_get_params_v3 { + struct apr_hdr apr_hdr; + struct mem_mapping_hdr mem_hdr; + struct param_hdr_v3 param_info; +} __packed; + struct lsm_param_op_mode { uint32_t minor_version; uint16_t mode; @@ -304,6 +318,9 @@ int q6lsm_lab_buffer_alloc(struct lsm_client *client, bool alloc); int q6lsm_set_one_param(struct lsm_client *client, struct lsm_params_info_v2 *p_info, void *data, uint32_t param_type); +int q6lsm_get_one_param(struct lsm_client *client, + struct lsm_params_get_info *p_info, + 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_sound_model *sm); diff --git a/include/uapi/audio/sound/lsm_params.h b/include/uapi/audio/sound/lsm_params.h index 722d3ba72677..c5945e19e867 100644 --- a/include/uapi/audio/sound/lsm_params.h +++ b/include/uapi/audio/sound/lsm_params.h @@ -36,7 +36,8 @@ #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_GET_CUSTOM_PARAMS (13) +#define LSM_PARAMS_MAX (LSM_GET_CUSTOM_PARAMS + 1) #define LSM_EVENT_NON_TIME_STAMP_MODE (0) #define LSM_EVENT_TIME_STAMP_MODE (1) @@ -288,6 +289,29 @@ struct snd_lsm_input_hw_params { __u16 num_channels; } __packed; +/* + * Param get info for each parameter type + * add "for SNDRV_LSM_GET_MODULE_PARAMS ioctl" + * Existing member variables: + * @module_id: Module to which parameter is to be set + * @instance_id: instance id of the param to which parameter is to be set + * @param_id: Parameter that is to be set + * @param_size: size of requested param + * @param_type: Parameter type as defined in values upto LSM_PARAMS_MAX + * @stage_idx: detection stage for which the param is applicable + * @payload: memory where requested param info will be populated + */ +struct lsm_params_get_info { + __u32 module_id; + __u16 instance_id; + __u16 reserved; + __u32 param_id; + __u32 param_size; + __u32 param_type; + __u16 stage_idx; + __u8 payload[0]; +} __packed; + #define SNDRV_LSM_DEREG_SND_MODEL _IOW('U', 0x01, int) #define SNDRV_LSM_EVENT_STATUS _IOW('U', 0x02, struct snd_lsm_event_status) #define SNDRV_LSM_ABORT_EVENT _IOW('U', 0x03, int) @@ -315,5 +339,6 @@ struct snd_lsm_input_hw_params { struct snd_lsm_session_data_v2) #define SNDRV_LSM_SET_MODULE_PARAMS_V2 _IOW('U', 0x13, \ struct snd_lsm_module_params) - +#define SNDRV_LSM_GET_MODULE_PARAMS _IOWR('U', 0x14, \ + struct lsm_params_get_info) #endif