ASoC: msm-cpe-lsm: Add support for openCPE

openCPE framework allows third party vendors to integrate audio/voice
processing algorithms into CPE. Add support for openCPE.

Change-Id: I8a0e00fa3dd74753834ba653b7ee3c84e72fd39e
Signed-off-by: Bhalchandra Gajare <gajare@codeaurora.org>
This commit is contained in:
Bhalchandra Gajare 2015-07-06 23:17:55 -07:00 committed by Chaithanya Krishna Bacharaju
parent 86ef8db1b1
commit c64ce2fc17
4 changed files with 1276 additions and 137 deletions

View File

@ -57,9 +57,14 @@
#define CPE_LSM_SESSION_CMDRSP_SHARED_MEM_ALLOC (0x2009)
#define CPE_LSM_SESSION_CMD_SHARED_MEM_DEALLOC (0x200A)
#define CPE_LSM_SESSION_CMD_TX_BUFF_OUTPUT_CONFIG (0x200f)
#define CPE_LSM_SESSION_CMD_OPEN_TX_V2 (0x200D)
#define CPE_LSM_SESSION_CMD_SET_PARAMS_V2 (0x200E)
/* LSM Service module and param IDs */
#define CPE_LSM_MODULE_ID_VOICE_WAKEUP (0x00012C00)
#define CPE_LSM_MODULE_ID_VOICE_WAKEUP_V2 (0x00012C0D)
#define CPE_LSM_MODULE_FRAMEWORK (0x00012C0E)
#define CPE_LSM_PARAM_ID_ENDPOINT_DETECT_THRESHOLD (0x00012C01)
#define CPE_LSM_PARAM_ID_OPERATION_MODE (0x00012C02)
#define CPE_LSM_PARAM_ID_GAIN (0x00012C03)
@ -73,6 +78,8 @@
#define CPE_LSM_PARAM_ID_LAB_ENABLE 0x00012C09
/* used for T in LAB config DSP internal buffer*/
#define CPE_LSM_PARAM_ID_LAB_CONFIG 0x00012C0A
#define CPE_LSM_PARAM_ID_REGISTER_SOUND_MODEL (0x00012C14)
#define CPE_LSM_PARAM_ID_DEREGISTER_SOUND_MODEL (0x00012C15)
/* AFE Service command opcodes */
#define CPE_AFE_PORT_CMD_START (0x1001)
@ -263,6 +270,11 @@ struct cpe_lsm_cmd_open_tx {
u32 sampling_rate;
} __packed;
struct cpe_lsm_cmd_open_tx_v2 {
struct cmi_hdr hdr;
u32 topology_id;
} __packed;
struct cpe_cmd_shmem_alloc {
struct cmi_hdr hdr;
u32 size;
@ -285,10 +297,35 @@ struct cpe_lsm_event_detect_v2 {
u8 payload[0];
} __packed;
struct cpe_lsm_psize_res {
u16 param_size;
u16 reserved;
} __packed;
union cpe_lsm_param_size {
u32 param_size;
struct cpe_lsm_psize_res sr;
} __packed;
struct cpe_param_data {
u32 module_id;
u32 param_id;
u16 param_size;
union cpe_lsm_param_size p_size;
} __packed;
struct cpe_lsm_param_epd_thres {
struct cmi_hdr hdr;
struct cpe_param_data param;
u32 minor_version;
u32 epd_begin;
u32 epd_end;
} __packed;
struct cpe_lsm_param_gain {
struct cmi_hdr hdr;
struct cpe_param_data param;
u32 minor_version;
u16 gain;
u16 reserved;
} __packed;
@ -319,14 +356,14 @@ struct cpe_afe_params {
struct cmi_hdr hdr;
struct cpe_afe_hw_mad_ctrl hw_mad_ctrl;
struct cpe_afe_port_cfg port_cfg;
};
} __packed;
struct cpe_afe_svc_cmd_mode {
struct cmi_hdr hdr;
u8 mode;
} __packed;
struct cpe_lsm_operation_mode {
struct cpe_lsm_param_opmode {
struct cmi_hdr hdr;
struct cpe_param_data param;
u32 minor_version;
@ -334,7 +371,7 @@ struct cpe_lsm_operation_mode {
u16 reserved;
} __packed;
struct cpe_lsm_connect_to_port {
struct cpe_lsm_param_connectport {
struct cmi_hdr hdr;
struct cpe_param_data param;
u32 minor_version;
@ -393,12 +430,6 @@ struct cpe_lsm_lab_latency_config {
sizeof(struct cmi_hdr))
#define PARAM_SIZE_LSM_CONTROL_SIZE (sizeof(struct cpe_lsm_lab_enable) - \
sizeof(struct cpe_param_data))
#define PARAM_SIZE_LSM_OP_MODE (sizeof(struct cpe_lsm_operation_mode) - \
sizeof(struct cmi_hdr) - \
sizeof(struct cpe_param_data))
#define PARAM_SIZE_LSM_CONNECT_PORT (sizeof(struct cpe_lsm_connect_to_port) - \
sizeof(struct cmi_hdr) - \
sizeof(struct cpe_param_data))
#define PARAM_SIZE_AFE_HW_MAD_CTRL (sizeof(struct cpe_afe_hw_mad_ctrl) - \
sizeof(struct cpe_param_data))
#define PARAM_SIZE_AFE_PORT_CFG (sizeof(struct cpe_afe_port_cfg) - \
@ -408,7 +439,8 @@ struct cpe_lsm_lab_latency_config {
#define OPEN_CMD_PAYLOAD_SIZE (sizeof(struct cpe_lsm_cmd_open_tx) - \
sizeof(struct cmi_hdr))
#define OPEN_V2_CMD_PAYLOAD_SIZE (sizeof(struct cpe_lsm_cmd_open_tx_v2) - \
sizeof(struct cmi_hdr))
#define SHMEM_ALLOC_CMD_PLD_SIZE (sizeof(struct cpe_cmd_shmem_alloc) - \
sizeof(struct cmi_hdr))
@ -425,4 +457,21 @@ struct cpe_lsm_lab_latency_config {
#define CPE_AFE_CMD_MODE_PAYLOAD_SIZE \
(sizeof(struct cpe_afe_svc_cmd_mode) - \
sizeof(struct cmi_hdr))
#define CPE_CMD_EPD_THRES_PLD_SIZE (sizeof(struct cpe_lsm_param_epd_thres) - \
sizeof(struct cmi_hdr))
#define CPE_EPD_THRES_PARAM_SIZE ((CPE_CMD_EPD_THRES_PLD_SIZE) - \
sizeof(struct cpe_param_data))
#define CPE_CMD_OPMODE_PLD_SIZE (sizeof(struct cpe_lsm_param_opmode) - \
sizeof(struct cmi_hdr))
#define CPE_OPMODE_PARAM_SIZE ((CPE_CMD_OPMODE_PLD_SIZE) -\
sizeof(struct cpe_param_data))
#define CPE_CMD_CONNECTPORT_PLD_SIZE \
(sizeof(struct cpe_lsm_param_connectport) - \
sizeof(struct cmi_hdr))
#define CPE_CONNECTPORT_PARAM_SIZE ((CPE_CMD_CONNECTPORT_PLD_SIZE) - \
sizeof(struct cpe_param_data))
#define CPE_CMD_GAIN_PLD_SIZE (sizeof(struct cpe_lsm_param_gain) - \
sizeof(struct cmi_hdr))
#define CPE_GAIN_PARAM_SIZE ((CPE_CMD_GAIN_PLD_SIZE) - \
sizeof(struct cpe_param_data))
#endif /* __CPE_CMI_H__ */

View File

@ -74,6 +74,8 @@ struct cpe_lsm_session {
u32 lab_enable;
struct lsm_out_fmt_cfg out_fmt_cfg;
bool is_topology_used;
};
struct wcd_cpe_afe_ops {
@ -149,6 +151,13 @@ struct wcd_cpe_lsm_ops {
int (*lsm_set_port)(void *core_handle,
struct cpe_lsm_session *session);
int (*lsm_set_one_param)(void *core_handle,
struct cpe_lsm_session *session,
struct lsm_params_info *p_info,
void *data, enum LSM_PARAM_TYPE param_type);
void (*lsm_get_snd_model_offset)
(void *core_handle, struct cpe_lsm_session *,
size_t *offset);
};
int wcd_cpe_get_lsm_ops(struct wcd_cpe_lsm_ops *);

View File

@ -94,6 +94,11 @@ struct wcd_cmi_afe_port_data {
u32 mem_handle;
};
struct cpe_lsm_ids {
u32 module_id;
u32 param_id;
};
static struct wcd_cpe_core *core_d;
static struct cpe_lsm_session
*lsm_sessions[WCD_CPE_LSM_MAX_SESSIONS + 1];
@ -2200,6 +2205,88 @@ static int wcd_cpe_is_valid_lsm_session(struct wcd_cpe_core *core,
return 0;
}
static int wcd_cpe_cmd_lsm_open_tx_v2(
struct wcd_cpe_core *core,
struct cpe_lsm_session *session)
{
struct cpe_lsm_cmd_open_tx_v2 cmd_open_tx_v2;
struct cal_block_data *top_cal = NULL;
struct audio_cal_info_lsm_top *lsm_top;
int ret = 0;
ret = wcd_cpe_is_valid_lsm_session(core, session,
__func__);
if (ret)
return ret;
if (core->cal_data[WCD_CPE_LSM_CAL_TOPOLOGY_ID] == NULL) {
dev_err(core->dev,
"%s: LSM_TOPOLOGY cal not allocated!\n",
__func__);
return -EINVAL;
}
mutex_lock(&core->cal_data[WCD_CPE_LSM_CAL_TOPOLOGY_ID]->lock);
top_cal = cal_utils_get_only_cal_block(
core->cal_data[WCD_CPE_LSM_CAL_TOPOLOGY_ID]);
if (!top_cal) {
dev_err(core->dev,
"%s: Failed to get LSM TOPOLOGY cal block\n",
__func__);
ret = -EINVAL;
goto unlock_cal_mutex;
}
lsm_top = (struct audio_cal_info_lsm_top *)
top_cal->cal_info;
if (!lsm_top) {
dev_err(core->dev,
"%s: cal_info for LSM_TOPOLOGY not found\n",
__func__);
ret = -EINVAL;
goto unlock_cal_mutex;
}
dev_dbg(core->dev,
"%s: topology_id = 0x%x, acdb_id = 0x%x, app_type = 0x%x\n",
__func__, lsm_top->topology, lsm_top->acdb_id,
lsm_top->app_type);
if (lsm_top->topology == 0) {
dev_err(core->dev,
"%s: topology id not sent for app_type 0x%x\n",
__func__, lsm_top->app_type);
ret = -EINVAL;
goto unlock_cal_mutex;
}
WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
memset(&cmd_open_tx_v2, 0, sizeof(struct cpe_lsm_cmd_open_tx_v2));
if (fill_lsm_cmd_header_v0_inband(&cmd_open_tx_v2.hdr,
session->id, OPEN_V2_CMD_PAYLOAD_SIZE,
CPE_LSM_SESSION_CMD_OPEN_TX_V2)) {
ret = -EINVAL;
goto end_ret;
}
cmd_open_tx_v2.topology_id = lsm_top->topology;
ret = wcd_cpe_cmi_send_lsm_msg(core, session, &cmd_open_tx_v2);
if (ret)
dev_err(core->dev,
"%s: failed to send open_tx_v2 cmd, err = %d\n",
__func__, ret);
else
session->is_topology_used = true;
end_ret:
WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
unlock_cal_mutex:
mutex_unlock(&core->cal_data[WCD_CPE_LSM_CAL_TOPOLOGY_ID]->lock);
return ret;
}
/*
* wcd_cpe_cmd_lsm_open_tx: compose and send lsm open command
* @core_handle: handle to cpe core
@ -2220,6 +2307,14 @@ static int wcd_cpe_cmd_lsm_open_tx(void *core_handle,
if (ret)
return ret;
/* Try to open with topology first */
ret = wcd_cpe_cmd_lsm_open_tx_v2(core, session);
if (!ret)
goto done;
dev_dbg(core->dev, "%s: Try open_tx without topology\n",
__func__);
WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
memset(&cmd_open_tx, 0, sizeof(struct cpe_lsm_cmd_open_tx));
@ -2240,6 +2335,7 @@ static int wcd_cpe_cmd_lsm_open_tx(void *core_handle,
__func__, ret);
end_ret:
WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
done:
return ret;
}
@ -2274,12 +2370,13 @@ static int wcd_cpe_cmd_lsm_close_tx(void *core_handle,
dev_err(core->dev,
"%s: lsm close_tx cmd failed, err = %d\n",
__func__, ret);
else
session->is_topology_used = false;
end_ret:
WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
return ret;
}
/*
* wcd_cpe_cmd_shmem_alloc: compose and send lsm shared
* memory allocation command
@ -2442,68 +2539,151 @@ unlock_cal_mutex:
}
/*
* wcd_cpe_lsm_set_opmode: set operation mode for listen
* @core: handle to cpe core
* @session: session for which the parameters are to be set
* @detect_mode: mode for detection
* @detect_failure: flag indicating failure detection enabled/disabled
*
*/
static int wcd_cpe_lsm_set_opmode(
struct wcd_cpe_core *core,
struct cpe_lsm_session *session,
enum lsm_detection_mode detect_mode,
bool detect_failure)
static void wcd_cpe_set_param_data(struct cpe_param_data *param_d,
struct cpe_lsm_ids *ids, u32 p_size,
u32 set_param_cmd)
{
struct cpe_lsm_operation_mode op_mode;
struct cmi_hdr *hdr = &op_mode.hdr;
struct cpe_param_data *param_d = &op_mode.param;
int ret = 0;
u8 pld_size = 0;
param_d->module_id = ids->module_id;
param_d->param_id = ids->param_id;
ret = wcd_cpe_send_lsm_cal(core, session);
if (ret) {
pr_err("%s: fail to sent acdb cal, err = %d\n",
__func__, ret);
return ret;
switch (set_param_cmd) {
case CPE_LSM_SESSION_CMD_SET_PARAMS_V2:
param_d->p_size.param_size = p_size;
break;
case CPE_LSM_SESSION_CMD_SET_PARAMS:
default:
param_d->p_size.sr.param_size =
(u16) p_size;
param_d->p_size.sr.reserved = 0;
break;
}
}
memset(&op_mode, 0, sizeof(struct cpe_lsm_operation_mode));
static int wcd_cpe_send_param_epd_thres(struct wcd_cpe_core *core,
struct cpe_lsm_session *session,
void *data, struct cpe_lsm_ids *ids)
{
struct snd_lsm_ep_det_thres *ep_det_data;
struct cpe_lsm_param_epd_thres epd_cmd;
struct cmi_hdr *msg_hdr = &epd_cmd.hdr;
struct cpe_param_data *param_d =
&epd_cmd.param;
int rc;
pld_size = (sizeof(struct cpe_lsm_operation_mode) -
sizeof(struct cmi_hdr));
if (fill_lsm_cmd_header_v0_inband(hdr,
memset(&epd_cmd, 0, sizeof(epd_cmd));
ep_det_data = (struct snd_lsm_ep_det_thres *) data;
if (fill_lsm_cmd_header_v0_inband(msg_hdr,
session->id,
pld_size,
CPE_LSM_SESSION_CMD_SET_PARAMS)) {
ret = -EINVAL;
CPE_CMD_EPD_THRES_PLD_SIZE,
CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
rc = -EINVAL;
goto err_ret;
}
param_d->module_id = CPE_LSM_MODULE_ID_VOICE_WAKEUP;
param_d->param_id = CPE_LSM_PARAM_ID_OPERATION_MODE;
param_d->param_size = PARAM_SIZE_LSM_OP_MODE;
param_d->reserved = 0;
wcd_cpe_set_param_data(param_d, ids,
CPE_EPD_THRES_PARAM_SIZE,
CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
op_mode.minor_version = 1;
if (detect_mode == LSM_MODE_KEYWORD_ONLY_DETECTION)
op_mode.mode = 1;
else
op_mode.mode = 3;
epd_cmd.minor_version = 0;
epd_cmd.epd_begin = ep_det_data->epd_begin;
epd_cmd.epd_end = ep_det_data->epd_end;
if (detect_failure)
op_mode.mode |= 0x04;
op_mode.reserved = 0;
ret = wcd_cpe_cmi_send_lsm_msg(core, session, &op_mode);
if (ret)
pr_err("%s: lsm_set_opmode failed, rc %d\n",
__func__, ret);
WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
rc = wcd_cpe_cmi_send_lsm_msg(core, session, &epd_cmd);
if (unlikely(rc))
dev_err(core->dev,
"%s: set_param(EPD Threshold) failed, rc %dn",
__func__, rc);
WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
err_ret:
return ret;
return rc;
}
static int wcd_cpe_send_param_opmode(struct wcd_cpe_core *core,
struct cpe_lsm_session *session,
void *data, struct cpe_lsm_ids *ids)
{
struct snd_lsm_detect_mode *opmode_d;
struct cpe_lsm_param_opmode opmode_cmd;
struct cmi_hdr *msg_hdr = &opmode_cmd.hdr;
struct cpe_param_data *param_d =
&opmode_cmd.param;
int rc;
memset(&opmode_cmd, 0, sizeof(opmode_cmd));
opmode_d = (struct snd_lsm_detect_mode *) data;
if (fill_lsm_cmd_header_v0_inband(msg_hdr,
session->id,
CPE_CMD_OPMODE_PLD_SIZE,
CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
rc = -EINVAL;
goto err_ret;
}
wcd_cpe_set_param_data(param_d, ids,
CPE_OPMODE_PARAM_SIZE,
CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
opmode_cmd.minor_version = 0;
if (opmode_d->mode == LSM_MODE_KEYWORD_ONLY_DETECTION)
opmode_cmd.mode = 1;
else
opmode_cmd.mode = 3;
if (opmode_d->detect_failure)
opmode_cmd.mode |= 0x04;
opmode_cmd.reserved = 0;
WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
rc = wcd_cpe_cmi_send_lsm_msg(core, session, &opmode_cmd);
if (unlikely(rc))
dev_err(core->dev,
"%s: set_param(operation_mode) failed, rc %dn",
__func__, rc);
WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
err_ret:
return rc;
}
static int wcd_cpe_send_param_gain(struct wcd_cpe_core *core,
struct cpe_lsm_session *session,
void *data, struct cpe_lsm_ids *ids)
{
struct snd_lsm_gain *gain_d;
struct cpe_lsm_param_gain gain_cmd;
struct cmi_hdr *msg_hdr = &gain_cmd.hdr;
struct cpe_param_data *param_d =
&gain_cmd.param;
int rc;
memset(&gain_cmd, 0, sizeof(gain_cmd));
gain_d = (struct snd_lsm_gain *) data;
if (fill_lsm_cmd_header_v0_inband(msg_hdr,
session->id,
CPE_CMD_GAIN_PLD_SIZE,
CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
rc = -EINVAL;
goto err_ret;
}
wcd_cpe_set_param_data(param_d, ids,
CPE_GAIN_PARAM_SIZE,
CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
gain_cmd.minor_version = 0;
gain_cmd.gain = gain_d->gain;
gain_cmd.reserved = 0;
WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
rc = wcd_cpe_cmi_send_lsm_msg(core, session, &gain_cmd);
if (unlikely(rc))
dev_err(core->dev,
"%s: set_param(lsm_gain) failed, rc %dn",
__func__, rc);
WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
err_ret:
return rc;
}
/*
@ -2511,65 +2691,58 @@ err_ret:
* @core: handle to cpe core
* @session: session for which the parameters are to be set
*/
static int wcd_cpe_lsm_set_port(void *core_handle,
struct cpe_lsm_session *session)
static int wcd_cpe_send_param_connectport(void *core_handle,
struct cpe_lsm_session *session)
{
struct cpe_lsm_connect_to_port connect_port;
struct cmi_hdr *hdr = &connect_port.hdr;
struct cpe_param_data *param_d = &connect_port.param;
struct wcd_cpe_core *core = core_handle;
int ret = 0;
u8 pld_size = 0;
struct cpe_lsm_param_connectport con_port_cmd;
struct cpe_lsm_ids ids;
struct cmi_hdr *msg_hdr = &con_port_cmd.hdr;
struct cpe_param_data *param_d =
&con_port_cmd.param;
int rc;
ret = wcd_cpe_is_valid_lsm_session(core, session,
__func__);
if (ret)
return ret;
if (session->is_topology_used) {
ids.module_id = LSM_MODULE_ID_FRAMEWORK;
ids.param_id = CPE_LSM_PARAM_ID_CONNECT_TO_PORT;
WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
} else {
ids.module_id = CPE_LSM_MODULE_ID_VOICE_WAKEUP;
ids.param_id = CPE_LSM_PARAM_ID_CONNECT_TO_PORT;
}
memset(&connect_port, 0, sizeof(struct cpe_lsm_connect_to_port));
pld_size = (sizeof(struct cpe_lsm_connect_to_port) -
sizeof(struct cmi_hdr));
if (fill_lsm_cmd_header_v0_inband(hdr,
memset(&con_port_cmd, 0, sizeof(con_port_cmd));
if (fill_lsm_cmd_header_v0_inband(msg_hdr,
session->id,
pld_size,
CPE_LSM_SESSION_CMD_SET_PARAMS)) {
ret = -EINVAL;
CPE_CMD_CONNECTPORT_PLD_SIZE,
CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
rc = -EINVAL;
goto err_ret;
}
param_d->module_id = CPE_LSM_MODULE_ID_VOICE_WAKEUP;
param_d->param_id = CPE_LSM_PARAM_ID_CONNECT_TO_PORT;
param_d->param_size = PARAM_SIZE_LSM_CONNECT_PORT;
param_d->reserved = 0;
wcd_cpe_set_param_data(param_d, &ids,
CPE_CONNECTPORT_PARAM_SIZE,
CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
connect_port.minor_version = 1;
connect_port.afe_port_id = CPE_AFE_PORT_1_TX;
connect_port.reserved = 0;
con_port_cmd.minor_version = 1;
con_port_cmd.afe_port_id = CPE_AFE_PORT_1_TX;
con_port_cmd.reserved = 0;
ret = wcd_cpe_cmi_send_lsm_msg(core, session, &connect_port);
if (ret)
pr_err("%s: lsm_set_port failed, rc %d\n",
__func__, ret);
err_ret:
WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
rc = wcd_cpe_cmi_send_lsm_msg(core, session, &con_port_cmd);
if (unlikely(rc))
dev_err(core->dev,
"%s: set_param(connect_port) failed, rc %dn",
__func__, rc);
WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
return ret;
err_ret:
return rc;
}
/*
* wcd_cpe_lsm_set_conf_levels: send the confidence levels for listen
* @core: handle to cpe core
* @session: session for which the confidence levels are to be set
*
* The actual confidence levels are part of the session.
*/
static int wcd_cpe_lsm_set_conf_levels(
struct wcd_cpe_core *core,
struct cpe_lsm_session *session)
static int wcd_cpe_send_param_conf_levels(
struct wcd_cpe_core *core,
struct cpe_lsm_session *session,
struct cpe_lsm_ids *ids)
{
struct cpe_lsm_conf_level conf_level_data;
struct cmi_hdr *hdr = &(conf_level_data.hdr);
@ -2588,13 +2761,11 @@ static int wcd_cpe_lsm_set_conf_levels(
fill_cmi_header(hdr, session->id, CMI_CPE_LSM_SERVICE_ID,
false, pld_size,
CPE_LSM_SESSION_CMD_SET_PARAMS, false);
CPE_LSM_SESSION_CMD_SET_PARAMS_V2, false);
param_d->module_id = CPE_LSM_MODULE_ID_VOICE_WAKEUP;
param_d->param_id = CPE_LSM_PARAM_ID_MIN_CONFIDENCE_LEVELS;
param_d->param_size = pld_size -
sizeof(struct cpe_param_data);
param_d->reserved = 0;
wcd_cpe_set_param_data(param_d, ids,
pld_size - sizeof(struct cpe_param_data),
CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
conf_level_data.num_active_models = session->num_confidence_levels;
@ -2611,11 +2782,228 @@ static int wcd_cpe_lsm_set_conf_levels(
memcpy(((u8 *) message) + sizeof(struct cpe_lsm_conf_level),
session->conf_levels, conf_level_data.num_active_models);
WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
ret = wcd_cpe_cmi_send_lsm_msg(core, session, message);
if (ret)
pr_err("%s: lsm_set_conf_levels failed, err = %d\n",
__func__, ret);
kfree(message);
WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
return ret;
}
static int wcd_cpe_send_param_snd_model(struct wcd_cpe_core *core,
struct cpe_lsm_session *session, struct cpe_lsm_ids *ids)
{
int ret = 0;
struct cmi_obm_msg obm_msg;
struct cpe_param_data *param_d;
ret = fill_cmi_header(&obm_msg.hdr, session->id,
CMI_CPE_LSM_SERVICE_ID, 0, 20,
CPE_LSM_SESSION_CMD_SET_PARAMS_V2, true);
if (ret) {
dev_err(core->dev,
"%s: Invalid parameters, rc = %d\n",
__func__, ret);
goto err_ret;
}
obm_msg.pld.version = 0;
obm_msg.pld.size = session->snd_model_size;
obm_msg.pld.data_ptr.kvaddr = session->snd_model_data;
obm_msg.pld.mem_handle = session->lsm_mem_handle;
param_d = (struct cpe_param_data *) session->snd_model_data;
wcd_cpe_set_param_data(param_d, ids,
(session->snd_model_size - sizeof(*param_d)),
CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
ret = wcd_cpe_cmi_send_lsm_msg(core, session, &obm_msg);
if (ret)
dev_err(core->dev,
"%s: snd_model_register failed, %d\n",
__func__, ret);
WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
err_ret:
return ret;
}
static int wcd_cpe_send_param_dereg_model(
struct wcd_cpe_core *core,
struct cpe_lsm_session *session,
struct cpe_lsm_ids *ids)
{
struct cmi_hdr *hdr;
struct cpe_param_data *param_d;
u8 *message;
u32 pld_size;
int rc = 0;
pld_size = sizeof(*hdr) + sizeof(*param_d);
message = kzalloc(pld_size, GFP_KERNEL);
if (!message)
return -ENOMEM;
hdr = (struct cmi_hdr *) message;
param_d = (struct cpe_param_data *)
(((u8 *) message) + sizeof(*hdr));
if (fill_lsm_cmd_header_v0_inband(hdr,
session->id,
sizeof(*param_d),
CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
rc = -EINVAL;
goto err_ret;
}
wcd_cpe_set_param_data(param_d, ids, 0,
CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
rc = wcd_cpe_cmi_send_lsm_msg(core, session, message);
if (rc)
dev_err(core->dev,
"%s: snd_model_deregister failed, %d\n",
__func__, rc);
WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
err_ret:
kfree(message);
return rc;
}
static int wcd_cpe_send_custom_param(
struct wcd_cpe_core *core,
struct cpe_lsm_session *session,
void *data, u32 msg_size)
{
u8 *msg;
struct cmi_hdr *hdr;
u8 *msg_pld;
int rc;
if (msg_size > CMI_INBAND_MESSAGE_SIZE) {
dev_err(core->dev,
"%s: out of band custom params not supported\n",
__func__);
return -EINVAL;
}
msg = kzalloc(sizeof(*hdr) + msg_size, GFP_KERNEL);
if (!msg)
return -ENOMEM;
hdr = (struct cmi_hdr *) msg;
msg_pld = msg + sizeof(struct cmi_hdr);
if (fill_lsm_cmd_header_v0_inband(hdr,
session->id,
msg_size,
CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
rc = -EINVAL;
goto err_ret;
}
memcpy(msg_pld, data, msg_size);
WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
rc = wcd_cpe_cmi_send_lsm_msg(core, session, msg);
if (rc)
dev_err(core->dev,
"%s: custom params send failed, err = %d\n",
__func__, rc);
WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
err_ret:
kfree(msg);
return rc;
}
static int wcd_cpe_set_one_param(void *core_handle,
struct cpe_lsm_session *session, struct lsm_params_info *p_info,
void *data, enum LSM_PARAM_TYPE param_type)
{
struct wcd_cpe_core *core = core_handle;
int rc = 0;
struct cpe_lsm_ids ids;
memset(&ids, 0, sizeof(ids));
ids.module_id = p_info->module_id;
ids.param_id = p_info->param_id;
switch (param_type) {
case LSM_ENDPOINT_DETECT_THRESHOLD:
rc = wcd_cpe_send_param_epd_thres(core, session,
data, &ids);
break;
case LSM_OPERATION_MODE:
rc = wcd_cpe_send_param_opmode(core, session,
data, &ids);
break;
case LSM_GAIN:
rc = wcd_cpe_send_param_gain(core, session, data, &ids);
break;
case LSM_MIN_CONFIDENCE_LEVELS:
rc = wcd_cpe_send_param_conf_levels(core, session, &ids);
break;
case LSM_REG_SND_MODEL:
rc = wcd_cpe_send_param_snd_model(core, session, &ids);
break;
case LSM_DEREG_SND_MODEL:
rc = wcd_cpe_send_param_dereg_model(core, session, &ids);
break;
case LSM_CUSTOM_PARAMS:
rc = wcd_cpe_send_custom_param(core, session,
data, p_info->param_size);
break;
default:
pr_err("%s: wrong param_type 0x%x\n",
__func__, p_info->param_type);
}
if (rc)
dev_err(core->dev,
"%s: send_param(%d) failed, err %d\n",
__func__, p_info->param_type, rc);
return rc;
}
/*
* wcd_cpe_lsm_set_params: set the parameters for lsm service
* @core: handle to cpe core
* @session: session for which the parameters are to be set
* @detect_mode: mode for detection
* @detect_failure: flag indicating failure detection enabled/disabled
*
*/
static int wcd_cpe_lsm_set_params(struct wcd_cpe_core *core,
struct cpe_lsm_session *session,
enum lsm_detection_mode detect_mode, bool detect_failure)
{
struct cpe_lsm_ids ids;
struct snd_lsm_detect_mode det_mode;
int ret = 0;
/* Send lsm calibration */
ret = wcd_cpe_send_lsm_cal(core, session);
if (ret) {
pr_err("%s: fail to sent acdb cal, err = %d",
__func__, ret);
return ret;
}
/* Send operation mode */
ids.module_id = CPE_LSM_MODULE_ID_VOICE_WAKEUP;
ids.param_id = CPE_LSM_PARAM_ID_OPERATION_MODE;
det_mode.mode = detect_mode;
det_mode.detect_failure = detect_failure;
ret = wcd_cpe_send_param_opmode(core, session,
&det_mode, &ids);
if (ret)
dev_err(core->dev,
"%s: Failed to set opmode, err=%d\n",
__func__, ret);
return ret;
}
@ -2625,11 +3013,11 @@ int wcd_cpe_lsm_set_data(void *core_handle,
bool detect_failure)
{
struct wcd_cpe_core *core = core_handle;
struct cpe_lsm_ids ids;
int ret = 0;
WCD_CPE_GRAB_LOCK(&session->lsm_lock, "lsm");
if (session->num_confidence_levels > 0) {
ret = wcd_cpe_lsm_set_opmode(core, session, detect_mode,
ret = wcd_cpe_lsm_set_params(core, session, detect_mode,
detect_failure);
if (ret) {
dev_err(core->dev,
@ -2638,7 +3026,9 @@ int wcd_cpe_lsm_set_data(void *core_handle,
goto err_ret;
}
ret = wcd_cpe_lsm_set_conf_levels(core, session);
ids.module_id = CPE_LSM_MODULE_ID_VOICE_WAKEUP;
ids.param_id = CPE_LSM_PARAM_ID_MIN_CONFIDENCE_LEVELS;
ret = wcd_cpe_send_param_conf_levels(core, session, &ids);
if (ret) {
dev_err(core->dev,
"%s: lsm confidence levels failed, rc = %d\n",
@ -2652,7 +3042,6 @@ int wcd_cpe_lsm_set_data(void *core_handle,
}
err_ret:
WCD_CPE_REL_LOCK(&session->lsm_lock, "lsm");
return ret;
}
EXPORT_SYMBOL(wcd_cpe_lsm_set_data);
@ -2946,9 +3335,11 @@ static int wcd_cpe_lsm_config_lab_latency(
int ret = 0, pld_size = CPE_PARAM_LSM_LAB_LATENCY_SIZE;
struct cpe_lsm_lab_latency_config cpe_lab_latency;
struct cpe_lsm_lab_config *lab_lat = &cpe_lab_latency.latency_cfg;
struct cpe_param_data *param_d = &lab_lat->param;
struct cpe_lsm_ids ids;
if (fill_lsm_cmd_header_v0_inband(&cpe_lab_latency.hdr, session->id,
(u8) pld_size, CPE_LSM_SESSION_CMD_SET_PARAMS)) {
(u8) pld_size, CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
pr_err("%s: Failed to create header\n", __func__);
return -EINVAL;
}
@ -2961,13 +3352,15 @@ static int wcd_cpe_lsm_config_lab_latency(
}
lab_lat->minor_ver = 1;
lab_lat->param.module_id = CPE_LSM_MODULE_ID_LAB;
lab_lat->param.param_id = CPE_LSM_PARAM_ID_LAB_CONFIG;
lab_lat->param.param_size = PARAM_SIZE_LSM_LATENCY_SIZE;
lab_lat->param.reserved = 0;
pr_debug("%s: Module 0x%x Param 0x%x size 0x%x pld_size 0x%x\n",
ids.module_id = CPE_LSM_MODULE_ID_LAB;
ids.param_id = CPE_LSM_PARAM_ID_LAB_CONFIG;
wcd_cpe_set_param_data(param_d, &ids,
PARAM_SIZE_LSM_LATENCY_SIZE,
CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
pr_debug("%s: Module 0x%x Param 0x%x size %ld pld_size 0x%x\n",
__func__, lab_lat->param.module_id,
lab_lat->param.param_id, lab_lat->param.param_size,
lab_lat->param.param_id, (long int)PARAM_SIZE_LSM_LATENCY_SIZE,
pld_size);
ret = wcd_cpe_cmi_send_lsm_msg(core, session, &cpe_lab_latency);
@ -2994,26 +3387,31 @@ static int wcd_cpe_lsm_lab_control(
int ret = 0, pld_size = CPE_PARAM_SIZE_LSM_LAB_CONTROL;
struct cpe_lsm_control_lab cpe_lab_enable;
struct cpe_lsm_lab_enable *lab_enable = &cpe_lab_enable.lab_enable;
struct cpe_param_data *param_d = &lab_enable->param;
struct cpe_lsm_ids ids;
pr_debug("%s: enter payload_size = %d Enable %d\n",
__func__, pld_size, enable);
if (fill_lsm_cmd_header_v0_inband(&cpe_lab_enable.hdr, session->id,
(u8) pld_size, CPE_LSM_SESSION_CMD_SET_PARAMS)) {
(u8) pld_size, CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
return -EINVAL;
}
if (enable == true)
lab_enable->enable = 1;
else
lab_enable->enable = 0;
lab_enable->param.module_id = CPE_LSM_MODULE_ID_LAB;
lab_enable->param.param_id = CPE_LSM_PARAM_ID_LAB_ENABLE;
lab_enable->param.param_size = PARAM_SIZE_LSM_CONTROL_SIZE;
lab_enable->param.reserved = 0;
pr_debug("%s: Module 0x%x, Param 0x%x size 0x%x pld_size 0x%x\n",
ids.module_id = CPE_LSM_MODULE_ID_LAB;
ids.param_id = CPE_LSM_PARAM_ID_LAB_ENABLE;
wcd_cpe_set_param_data(param_d, &ids,
PARAM_SIZE_LSM_CONTROL_SIZE,
CPE_LSM_SESSION_CMD_SET_PARAMS_V2);
pr_debug("%s: Module 0x%x, Param 0x%x size %ld pld_size 0x%x\n",
__func__, lab_enable->param.module_id,
lab_enable->param.param_id, lab_enable->param.param_size,
pld_size);
lab_enable->param.param_id,
(long int)PARAM_SIZE_LSM_CONTROL_SIZE, pld_size);
ret = wcd_cpe_cmi_send_lsm_msg(core, session, &cpe_lab_enable);
if (ret != 0) {
pr_err("%s: lsm_set_params failed, error = %d\n",
@ -3256,6 +3654,12 @@ done:
return ret;
}
static void wcd_cpe_snd_model_offset(void *core_handle,
struct cpe_lsm_session *session, size_t *offset)
{
*offset = sizeof(struct cpe_param_data);
}
/*
* wcd_cpe_get_lsm_ops: register lsm driver to codec
* @lsm_ops: structure with lsm callbacks
@ -3277,7 +3681,9 @@ int wcd_cpe_get_lsm_ops(struct wcd_cpe_lsm_ops *lsm_ops)
lsm_ops->lab_ch_setup = wcd_cpe_lab_ch_setup;
lsm_ops->lsm_set_data = wcd_cpe_lsm_set_data;
lsm_ops->lsm_set_fmt_cfg = wcd_cpe_lsm_set_fmt_cfg;
lsm_ops->lsm_set_port = wcd_cpe_lsm_set_port;
lsm_ops->lsm_set_port = wcd_cpe_send_param_connectport;
lsm_ops->lsm_set_one_param = wcd_cpe_set_one_param;
lsm_ops->lsm_get_snd_model_offset = wcd_cpe_snd_model_offset;
return 0;
}
EXPORT_SYMBOL(wcd_cpe_get_lsm_ops);
@ -3731,16 +4137,16 @@ static int wcd_cpe_afe_set_params(void *core_handle,
hw_mad_ctrl->param.module_id = CPE_AFE_MODULE_HW_MAD;
hw_mad_ctrl->param.param_id = CPE_AFE_PARAM_ID_HW_MAD_CTL;
hw_mad_ctrl->param.param_size = PARAM_SIZE_AFE_HW_MAD_CTRL;
hw_mad_ctrl->param.reserved = 0;
hw_mad_ctrl->param.p_size.sr.param_size = PARAM_SIZE_AFE_HW_MAD_CTRL;
hw_mad_ctrl->param.p_size.sr.reserved = 0;
hw_mad_ctrl->minor_version = 1;
hw_mad_ctrl->mad_type = MAD_TYPE_AUDIO;
hw_mad_ctrl->mad_enable = 1;
port_cfg->param.module_id = CPE_AFE_MODULE_AUDIO_DEV_INTERFACE;
port_cfg->param.param_id = CPE_AFE_PARAM_ID_GENERIC_PORT_CONFIG;
port_cfg->param.param_size = PARAM_SIZE_AFE_PORT_CFG;
port_cfg->param.reserved = 0;
port_cfg->param.p_size.sr.param_size = PARAM_SIZE_AFE_PORT_CFG;
port_cfg->param.p_size.sr.reserved = 0;
port_cfg->minor_version = 1;
port_cfg->bit_width = afe_cfg->bit_width;
port_cfg->num_channels = afe_cfg->num_channels;

View File

@ -35,6 +35,7 @@
#define LISTEN_MAX_PERIOD_SIZE 4096
#define LISTEN_MIN_PERIOD_SIZE 320
#define LISTEN_MAX_STATUS_PAYLOAD_SIZE 256
#define MSM_CPE_MAX_CUSTOM_PARAM_SIZE 2048
#define MSM_CPE_LAB_THREAD_TIMEOUT (3 * (HZ/10))
@ -1591,6 +1592,446 @@ static int msm_cpe_lsm_lab_start(struct snd_pcm_substream *substream,
return 0;
}
static bool msm_cpe_lsm_is_valid_stream(struct snd_pcm_substream *substream,
const char *func)
{
struct snd_soc_pcm_runtime *rtd;
struct cpe_lsm_data *lsm_d = NULL;
struct cpe_priv *cpe = NULL;
struct cpe_lsm_session *session = NULL;
struct wcd_cpe_lsm_ops *lsm_ops;
if (!substream || !substream->private_data) {
pr_err("%s: invalid substream (%p)\n",
func, substream);
return false;
}
rtd = substream->private_data;
lsm_d = cpe_get_lsm_data(substream);
cpe = cpe_get_private_data(substream);
if (!cpe || !cpe->core_handle) {
dev_err(rtd->dev,
"%s: Invalid private data\n",
func);
return false;
}
if (!lsm_d || !lsm_d->lsm_session) {
dev_err(rtd->dev,
"%s: Invalid session data\n",
func);
return false;
}
session = lsm_d->lsm_session;
lsm_ops = &cpe->lsm_ops;
if (!lsm_ops) {
dev_err(rtd->dev,
"%s: Invalid lsm_ops\n", func);
return false;
}
return true;
}
static int msm_cpe_lsm_set_epd(struct snd_pcm_substream *substream,
struct lsm_params_info *p_info)
{
struct snd_soc_pcm_runtime *rtd;
struct cpe_lsm_data *lsm_d = NULL;
struct cpe_priv *cpe = NULL;
struct cpe_lsm_session *session = NULL;
struct wcd_cpe_lsm_ops *lsm_ops;
struct snd_lsm_ep_det_thres epd_thres;
int rc;
if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
return -EINVAL;
rtd = substream->private_data;
lsm_d = cpe_get_lsm_data(substream);
cpe = cpe_get_private_data(substream);
session = lsm_d->lsm_session;
lsm_ops = &cpe->lsm_ops;
if (p_info->param_size != sizeof(epd_thres)) {
dev_err(rtd->dev,
"%s: Invalid param_size %d\n",
__func__, p_info->param_size);
rc = -EINVAL;
goto done;
}
if (copy_from_user(&epd_thres, p_info->param_data,
p_info->param_size)) {
dev_err(rtd->dev,
"%s: copy_from_user failed, size = %d\n",
__func__, p_info->param_size);
rc = -EFAULT;
goto done;
}
rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
session, p_info, &epd_thres,
LSM_ENDPOINT_DETECT_THRESHOLD);
if (unlikely(rc))
dev_err(rtd->dev,
"%s: set_one_param(epd_threshold) failed, rc %d\n",
__func__, rc);
done:
return rc;
}
static int msm_cpe_lsm_set_mode(struct snd_pcm_substream *substream,
struct lsm_params_info *p_info)
{
struct snd_soc_pcm_runtime *rtd;
struct cpe_lsm_data *lsm_d = NULL;
struct cpe_priv *cpe = NULL;
struct cpe_lsm_session *session = NULL;
struct wcd_cpe_lsm_ops *lsm_ops;
struct snd_lsm_detect_mode det_mode;
int rc;
if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
return -EINVAL;
rtd = substream->private_data;
lsm_d = cpe_get_lsm_data(substream);
cpe = cpe_get_private_data(substream);
session = lsm_d->lsm_session;
lsm_ops = &cpe->lsm_ops;
if (p_info->param_size != sizeof(det_mode)) {
dev_err(rtd->dev,
"%s: Invalid param_size %d\n",
__func__, p_info->param_size);
rc = -EINVAL;
goto done;
}
if (copy_from_user(&det_mode, p_info->param_data,
p_info->param_size)) {
dev_err(rtd->dev,
"%s: copy_from_user failed, size = %d\n",
__func__, p_info->param_size);
rc = -EFAULT;
goto done;
}
rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
session, p_info, &det_mode,
LSM_OPERATION_MODE);
if (unlikely(rc))
dev_err(rtd->dev,
"%s: set_one_param(epd_threshold) failed, rc %d\n",
__func__, rc);
done:
return rc;
}
static int msm_cpe_lsm_set_gain(struct snd_pcm_substream *substream,
struct lsm_params_info *p_info)
{
struct snd_soc_pcm_runtime *rtd;
struct cpe_lsm_data *lsm_d = NULL;
struct cpe_priv *cpe = NULL;
struct cpe_lsm_session *session = NULL;
struct wcd_cpe_lsm_ops *lsm_ops;
struct snd_lsm_gain gain;
int rc;
if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
return -EINVAL;
rtd = substream->private_data;
lsm_d = cpe_get_lsm_data(substream);
cpe = cpe_get_private_data(substream);
session = lsm_d->lsm_session;
lsm_ops = &cpe->lsm_ops;
if (p_info->param_size != sizeof(gain)) {
dev_err(rtd->dev,
"%s: Invalid param_size %d\n",
__func__, p_info->param_size);
rc = -EINVAL;
goto done;
}
if (copy_from_user(&gain, p_info->param_data,
p_info->param_size)) {
dev_err(rtd->dev,
"%s: copy_from_user failed, size = %d\n",
__func__, p_info->param_size);
rc = -EFAULT;
goto done;
}
rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
session, p_info, &gain,
LSM_GAIN);
if (unlikely(rc))
dev_err(rtd->dev,
"%s: set_one_param(epd_threshold) failed, rc %d\n",
__func__, rc);
done:
return rc;
}
static int msm_cpe_lsm_set_conf(struct snd_pcm_substream *substream,
struct lsm_params_info *p_info)
{
struct snd_soc_pcm_runtime *rtd;
struct cpe_lsm_data *lsm_d = NULL;
struct cpe_priv *cpe = NULL;
struct cpe_lsm_session *session = NULL;
struct wcd_cpe_lsm_ops *lsm_ops;
int rc;
if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
return -EINVAL;
rtd = substream->private_data;
lsm_d = cpe_get_lsm_data(substream);
cpe = cpe_get_private_data(substream);
session = lsm_d->lsm_session;
lsm_ops = &cpe->lsm_ops;
session->num_confidence_levels =
p_info->param_size;
rc = msm_cpe_lsm_get_conf_levels(session,
p_info->param_data);
if (rc) {
dev_err(rtd->dev,
"%s: get_conf_levels failed, err = %d\n",
__func__, rc);
goto done;
}
rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
session, p_info, NULL,
LSM_MIN_CONFIDENCE_LEVELS);
if (unlikely(rc))
dev_err(rtd->dev,
"%s: set_one_param(conf_levels) failed, rc %d\n",
__func__, rc);
done:
return rc;
}
static int msm_cpe_lsm_reg_model(struct snd_pcm_substream *substream,
struct lsm_params_info *p_info)
{
struct snd_soc_pcm_runtime *rtd;
struct cpe_lsm_data *lsm_d = NULL;
struct cpe_priv *cpe = NULL;
struct cpe_lsm_session *session = NULL;
struct wcd_cpe_lsm_ops *lsm_ops;
int rc;
size_t offset;
u8 *snd_model_ptr;
if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
return -EINVAL;
rtd = substream->private_data;
lsm_d = cpe_get_lsm_data(substream);
cpe = cpe_get_private_data(substream);
session = lsm_d->lsm_session;
lsm_ops = &cpe->lsm_ops;
lsm_ops->lsm_get_snd_model_offset(cpe->core_handle,
session, &offset);
session->snd_model_size = p_info->param_size + offset;
session->snd_model_data = vzalloc(session->snd_model_size);
if (!session->snd_model_data)
return -ENOMEM;
snd_model_ptr = ((u8 *) session->snd_model_data) + offset;
if (copy_from_user(snd_model_ptr,
p_info->param_data, p_info->param_size)) {
dev_err(rtd->dev,
"%s: copy_from_user for snd_model failed\n",
__func__);
rc = -EFAULT;
goto free_snd_model_data;
}
rc = lsm_ops->lsm_shmem_alloc(cpe->core_handle, session,
session->snd_model_size);
if (rc != 0) {
dev_err(rtd->dev,
"%s: shared memory allocation failed, err = %d\n",
__func__, rc);
rc = -EINVAL;
goto free_snd_model_data;
}
rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
session, p_info, NULL,
LSM_REG_SND_MODEL);
if (unlikely(rc)) {
dev_err(rtd->dev,
"%s: set_one_param(snd_model) failed, rc %d\n",
__func__, rc);
goto dealloc_shmem;
}
return 0;
dealloc_shmem:
lsm_ops->lsm_shmem_dealloc(cpe->core_handle, session);
free_snd_model_data:
vfree(session->snd_model_data);
return rc;
}
static int msm_cpe_lsm_dereg_model(struct snd_pcm_substream *substream,
struct lsm_params_info *p_info)
{
struct snd_soc_pcm_runtime *rtd;
struct cpe_lsm_data *lsm_d = NULL;
struct cpe_priv *cpe = NULL;
struct cpe_lsm_session *session = NULL;
struct wcd_cpe_lsm_ops *lsm_ops;
int rc;
if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
return -EINVAL;
rtd = substream->private_data;
lsm_d = cpe_get_lsm_data(substream);
cpe = cpe_get_private_data(substream);
session = lsm_d->lsm_session;
lsm_ops = &cpe->lsm_ops;
rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
session, p_info, NULL,
LSM_DEREG_SND_MODEL);
if (rc)
dev_err(rtd->dev,
"%s: dereg_snd_model failed\n",
__func__);
return lsm_ops->lsm_shmem_dealloc(cpe->core_handle, session);
}
static int msm_cpe_lsm_set_custom(struct snd_pcm_substream *substream,
struct lsm_params_info *p_info)
{
struct snd_soc_pcm_runtime *rtd;
struct cpe_lsm_data *lsm_d = NULL;
struct cpe_priv *cpe = NULL;
struct cpe_lsm_session *session = NULL;
struct wcd_cpe_lsm_ops *lsm_ops;
u8 *data;
int rc;
if (!msm_cpe_lsm_is_valid_stream(substream, __func__))
return -EINVAL;
rtd = substream->private_data;
lsm_d = cpe_get_lsm_data(substream);
cpe = cpe_get_private_data(substream);
session = lsm_d->lsm_session;
lsm_ops = &cpe->lsm_ops;
if (p_info->param_size > MSM_CPE_MAX_CUSTOM_PARAM_SIZE) {
dev_err(rtd->dev,
"%s: invalid size %d, max allowed %d\n",
__func__, p_info->param_size,
MSM_CPE_MAX_CUSTOM_PARAM_SIZE);
return -EINVAL;
}
data = kzalloc(p_info->param_size, GFP_KERNEL);
if (!data)
return -ENOMEM;
if (copy_from_user(data, p_info->param_data,
p_info->param_size)) {
dev_err(rtd->dev,
"%s: copy_from_user failed for custom params, size = %d\n",
__func__, p_info->param_size);
rc = -EFAULT;
goto err_ret;
}
rc = lsm_ops->lsm_set_one_param(cpe->core_handle,
session, p_info, data,
LSM_CUSTOM_PARAMS);
if (rc)
dev_err(rtd->dev,
"%s: custom_params failed, err = %d\n",
__func__, rc);
err_ret:
kfree(data);
return rc;
}
static int msm_cpe_lsm_process_params(struct snd_pcm_substream *substream,
struct snd_lsm_module_params *p_data,
void *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct lsm_params_info *p_info;
int i;
int rc = 0;
p_info = (struct lsm_params_info *) params;
for (i = 0; i < p_data->num_params; i++) {
dev_dbg(rtd->dev,
"%s: param (%d), module_id = 0x%x, param_id = 0x%x, param_size = 0x%x, param_type = 0x%x\n",
__func__, i, p_info->module_id,
p_info->param_id, p_info->param_size,
p_info->param_type);
switch (p_info->param_type) {
case LSM_ENDPOINT_DETECT_THRESHOLD:
rc = msm_cpe_lsm_set_epd(substream, p_info);
break;
case LSM_OPERATION_MODE:
rc = msm_cpe_lsm_set_mode(substream, p_info);
break;
case LSM_GAIN:
rc = msm_cpe_lsm_set_gain(substream, p_info);
break;
case LSM_MIN_CONFIDENCE_LEVELS:
rc = msm_cpe_lsm_set_conf(substream, p_info);
break;
case LSM_REG_SND_MODEL:
rc = msm_cpe_lsm_reg_model(substream, p_info);
break;
case LSM_DEREG_SND_MODEL:
rc = msm_cpe_lsm_dereg_model(substream, p_info);
break;
case LSM_CUSTOM_PARAMS:
rc = msm_cpe_lsm_set_custom(substream, p_info);
break;
default:
dev_err(rtd->dev,
"%s: Invalid param_type %d\n",
__func__, p_info->param_type);
rc = -EINVAL;
break;
}
if (rc) {
pr_err("%s: set_param fail for param_type %d\n",
__func__, p_info->param_type);
break;
}
p_info++;
}
return rc;
}
static int msm_cpe_lsm_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
{
@ -1634,6 +2075,15 @@ static int msm_cpe_lsm_ioctl(struct snd_pcm_substream *substream,
switch (cmd) {
case SNDRV_LSM_REG_SND_MODEL_V2: {
struct snd_lsm_sound_model_v2 snd_model;
if (session->is_topology_used) {
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "LSM_REG_SND_MODEL_V2");
err = -EINVAL;
goto done;
}
if (copy_from_user(&snd_model, (void *)arg,
sizeof(struct snd_lsm_sound_model_v2))) {
dev_err(rtd->dev,
@ -1707,6 +2157,14 @@ static int msm_cpe_lsm_ioctl(struct snd_pcm_substream *substream,
case SNDRV_LSM_SET_PARAMS: {
struct snd_lsm_detection_params det_params;
if (session->is_topology_used) {
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "SNDRV_LSM_SET_PARAMS");
err = -EINVAL;
goto done;
}
if (copy_from_user(&det_params, (void *) arg,
sizeof(det_params))) {
dev_err(rtd->dev,
@ -1721,6 +2179,81 @@ static int msm_cpe_lsm_ioctl(struct snd_pcm_substream *substream,
&det_params);
}
break;
case SNDRV_LSM_SET_MODULE_PARAMS: {
struct snd_lsm_module_params p_data;
size_t p_size;
u8 *params;
if (!session->is_topology_used) {
dev_err(rtd->dev,
"%s: %s: not supported if not using topology\n",
__func__, "SET_MODULE_PARAMS");
err = -EINVAL;
goto done;
}
if (!arg) {
dev_err(rtd->dev,
"%s: %s: No Param data to set\n",
__func__, "SET_MODULE_PARAMS");
err = -EINVAL;
goto done;
}
if (copy_from_user(&p_data, arg,
sizeof(p_data))) {
dev_err(rtd->dev,
"%s: %s: copy_from_user failed, size = %zd\n",
__func__, "p_data", sizeof(p_data));
err = -EFAULT;
goto done;
}
if (p_data.num_params > LSM_PARAMS_MAX) {
dev_err(rtd->dev,
"%s: %s: Invalid num_params %d\n",
__func__, "SET_MODULE_PARAMS",
p_data.num_params);
err = -EINVAL;
goto done;
}
p_size = p_data.num_params *
sizeof(struct lsm_params_info);
if (p_data.data_size != p_size) {
dev_err(rtd->dev,
"%s: %s: Invalid size %zd\n",
__func__, "SET_MODULE_PARAMS", p_size);
err = -EFAULT;
goto done;
}
params = kzalloc(p_size, GFP_KERNEL);
if (!params) {
err = -ENOMEM;
goto done;
}
if (copy_from_user(params, p_data.params,
p_data.data_size)) {
dev_err(rtd->dev,
"%s: %s: copy_from_user failed, size = %d\n",
__func__, "params", p_data.data_size);
kfree(params);
err = -EFAULT;
goto done;
}
err = msm_cpe_lsm_process_params(substream, &p_data, params);
if (err)
dev_err(rtd->dev,
"%s: %s: Failed to set params, err = %d\n",
__func__, "SET_MODULE_PARAMS", err);
kfree(params);
break;
}
default:
err = msm_cpe_lsm_ioctl_shared(substream, cmd, arg);
break;
@ -1755,6 +2288,20 @@ struct snd_lsm_detection_params_32 {
bool detect_failure;
};
struct lsm_params_info_32 {
u32 module_id;
u32 param_id;
u32 param_size;
compat_uptr_t param_data;
enum LSM_PARAM_TYPE param_type;
};
struct snd_lsm_module_params_32 {
compat_uptr_t params;
u32 num_params;
u32 data_size;
};
enum {
SNDRV_LSM_EVENT_STATUS32 =
_IOW('U', 0x02, struct snd_lsm_event_status32),
@ -1762,6 +2309,8 @@ enum {
_IOW('U', 0x07, struct snd_lsm_sound_model_v2_32),
SNDRV_LSM_SET_PARAMS32 =
_IOW('U', 0x0A, struct snd_lsm_detection_params_32),
SNDRV_LSM_SET_MODULE_PARAMS_32 =
_IOW('U', 0x0B, struct snd_lsm_module_params_32),
};
static int msm_cpe_lsm_ioctl_compat(struct snd_pcm_substream *substream,
@ -1809,6 +2358,14 @@ static int msm_cpe_lsm_ioctl_compat(struct snd_pcm_substream *substream,
struct snd_lsm_sound_model_v2 snd_model;
struct snd_lsm_sound_model_v2_32 snd_model32;
if (session->is_topology_used) {
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "LSM_REG_SND_MODEL_V2_32");
err = -EINVAL;
goto done;
}
dev_dbg(rtd->dev,
"%s: ioctl %s\n", __func__,
"SNDRV_LSM_REG_SND_MODEL_V2_32");
@ -1932,6 +2489,15 @@ static int msm_cpe_lsm_ioctl_compat(struct snd_pcm_substream *substream,
case SNDRV_LSM_SET_PARAMS32: {
struct snd_lsm_detection_params_32 det_params32;
struct snd_lsm_detection_params det_params;
if (session->is_topology_used) {
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "SNDRV_LSM_SET_PARAMS32");
err = -EINVAL;
goto done;
}
if (copy_from_user(&det_params32, arg,
sizeof(det_params32))) {
err = -EFAULT;
@ -1960,6 +2526,115 @@ static int msm_cpe_lsm_ioctl_compat(struct snd_pcm_substream *substream,
break;
}
case SNDRV_LSM_SET_MODULE_PARAMS_32: {
struct snd_lsm_module_params_32 p_data_32;
struct snd_lsm_module_params p_data;
u8 *params, *params32;
size_t p_size;
struct lsm_params_info_32 *p_info_32;
struct lsm_params_info *p_info;
int i;
if (!session->is_topology_used) {
dev_err(rtd->dev,
"%s: %s: not supported if not using topology\n",
__func__, "SET_MODULE_PARAMS_32");
err = -EINVAL;
goto done;
}
if (!arg) {
dev_err(rtd->dev,
"%s: %s: No Param data to set\n",
__func__, "SET_MODULE_PARAMS_32");
err = -EINVAL;
goto done;
}
if (copy_from_user(&p_data_32, arg,
sizeof(p_data_32))) {
dev_err(rtd->dev,
"%s: %s: copy_from_user failed, size = %zd\n",
__func__, "SET_MODULE_PARAMS_32",
sizeof(p_data_32));
err = -EFAULT;
goto done;
}
p_data.params = compat_ptr(p_data_32.params);
p_data.num_params = p_data_32.num_params;
p_data.data_size = p_data_32.data_size;
if (p_data.num_params > LSM_PARAMS_MAX) {
dev_err(rtd->dev,
"%s: %s: Invalid num_params %d\n",
__func__, "SET_MODULE_PARAMS_32",
p_data.num_params);
err = -EINVAL;
goto done;
}
if (p_data.data_size !=
(p_data.num_params * sizeof(struct lsm_params_info_32))) {
dev_err(rtd->dev,
"%s: %s: Invalid size %d\n",
__func__, "SET_MODULE_PARAMS_32",
p_data.data_size);
err = -EINVAL;
goto done;
}
p_size = sizeof(struct lsm_params_info_32) *
p_data.num_params;
params32 = kzalloc(p_size, GFP_KERNEL);
if (!params32) {
err = -ENOMEM;
goto done;
}
p_size = sizeof(struct lsm_params_info) * p_data.num_params;
params = kzalloc(p_size, GFP_KERNEL);
if (!params) {
kfree(params32);
err = -ENOMEM;
goto done;
}
if (copy_from_user(params32, p_data.params,
p_data.data_size)) {
dev_err(rtd->dev,
"%s: %s: copy_from_user failed, size = %d\n",
__func__, "params32", p_data.data_size);
kfree(params32);
kfree(params);
err = -EFAULT;
goto done;
}
p_info_32 = (struct lsm_params_info_32 *) params32;
p_info = (struct lsm_params_info *) params;
for (i = 0; i < p_data.num_params; i++) {
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_data = compat_ptr(p_info_32->param_data);
p_info->param_type = p_info_32->param_type;
p_info_32++;
p_info++;
}
err = msm_cpe_lsm_process_params(substream,
&p_data, params);
if (err)
dev_err(rtd->dev,
"%s: Failed to process params, err = %d\n",
__func__, err);
kfree(params);
kfree(params32);
break;
}
default:
err = msm_cpe_lsm_ioctl_shared(substream, cmd, arg);
break;