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

Commit 078c3505 authored by Chaithanya Krishna Bacharaju's avatar Chaithanya Krishna Bacharaju Committed by Gerrit - the friendly Code Review server
Browse files

ASoC: msm: qdsp6v2: Add timestamp support for lsm detection event



Add support to parse LSM_SESSION_EVENT_DETECTION_STATUS_V3
in cases where event status requires timestamp corresponding
to detection.

Framework mode config is set to timestamp mode in cases where
LSM_SESSION_EVENT_DETECTION_STATUS_V3 is required.

Change-Id: Id0da3b24d55ac56ff6b61372ede9c63f50b2f4d4
Signed-off-by: default avatarChaithanya Krishna Bacharaju <chaithan@codeaurora.org>
Signed-off-by: default avatarRevathi Uddaraju <revathiu@codeaurora.org>
parent 5ac11519
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -8352,6 +8352,7 @@ struct asm_dts_eagle_param_get {
#define LSM_SESSION_EVENT_DETECTION_STATUS_V2		(0x00012B01)
#define LSM_DATA_EVENT_READ_DONE			(0x00012B02)
#define LSM_DATA_EVENT_STATUS				(0x00012B03)
#define LSM_SESSION_EVENT_DETECTION_STATUS_V3		(0x00012B04)

#define LSM_MODULE_ID_VOICE_WAKEUP			(0x00012C00)
#define LSM_PARAM_ID_ENDPOINT_DETECT_THRESHOLD		(0x00012C01)
@@ -8368,6 +8369,7 @@ struct asm_dts_eagle_param_get {
#define LSM_PARAM_ID_SWMAD_MODEL			(0x00012C19)
#define LSM_PARAM_ID_SWMAD_ENABLE			(0x00012C1A)
#define LSM_PARAM_ID_POLLING_ENABLE			(0x00012C1B)
#define LSM_PARAM_ID_FWK_MODE_CONFIG			(0x00012C27)

/* HW MAD specific */
#define AFE_MODULE_HW_MAD				(0x00010230)
+14 −0
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ struct lsm_client {
	int		session_state;
	bool		poll_enable;
	int		perf_mode;
	uint32_t	event_mode;
};

struct lsm_stream_cmd_open_tx {
@@ -146,6 +147,12 @@ struct lsm_param_poll_enable {
	uint32_t	polling_enable;
} __packed;

struct lsm_param_fwk_mode_cfg {
	struct lsm_param_payload_common common;
	uint32_t	minor_version;
	uint32_t	mode;
} __packed;

/*
 * This param cannot be sent in this format.
 * The actual number of confidence level values
@@ -272,6 +279,12 @@ struct lsm_cmd_read_done {
	uint32_t flags;
} __packed;

struct lsm_cmd_set_fwk_mode_cfg {
	struct apr_hdr  msg_hdr;
	struct lsm_set_params_hdr params_hdr;
	struct lsm_param_fwk_mode_cfg fwk_mode_cfg;
} __packed;

struct lsm_client *q6lsm_client_alloc(lsm_app_cb cb, void *priv);
void q6lsm_client_free(struct lsm_client *client);
int q6lsm_open(struct lsm_client *client, uint16_t app_id);
@@ -302,4 +315,5 @@ void q6lsm_sm_set_param_data(struct lsm_client *client,
		size_t *offset);
int q6lsm_set_port_connected(struct lsm_client *client);
int q6lsm_polling_enable(struct lsm_client *client, bool poll_enable);
int q6lsm_set_fwk_mode_cfg(struct lsm_client *client, uint32_t event_mode);
#endif /* __Q6LSM_H__ */
+241 −16
Original line number Diff line number Diff line
@@ -82,7 +82,7 @@ static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
struct lsm_priv {
	struct snd_pcm_substream *substream;
	struct lsm_client *lsm_client;
	struct snd_lsm_event_status *event_status;
	struct snd_lsm_event_status_v3 *event_status;
	spinlock_t event_lock;
	wait_queue_head_t event_wait;
	unsigned long event_avail;
@@ -207,6 +207,8 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token,
	uint16_t status = 0;
	uint16_t payload_size = 0;
	uint16_t index = 0;
	uint32_t event_ts_lsw = 0;
	uint32_t event_ts_msw = 0;

	if (!substream || !substream->private_data) {
		pr_err("%s: Invalid %s\n", __func__,
@@ -280,24 +282,44 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token,
			"%s: event detect status = %d payload size = %d\n",
			__func__, status , payload_size);
		break;

	case LSM_SESSION_EVENT_DETECTION_STATUS_V3:
		event_ts_lsw = ((uint32_t *)payload)[0];
		event_ts_msw = ((uint32_t *)payload)[1];
		status = (uint16_t)((uint8_t *)payload)[8];
		payload_size = (uint16_t)((uint8_t *)payload)[9];
		index = 10;
		dev_dbg(rtd->dev,
			"%s: ts_msw = %u, ts_lsw = %u, event detect status = %d payload size = %d\n",
			__func__, event_ts_msw, event_ts_lsw, status,
			payload_size);
		break;

	default:
		break;
	}

	if (opcode == LSM_SESSION_EVENT_DETECTION_STATUS ||
		opcode == LSM_SESSION_EVENT_DETECTION_STATUS_V2) {
		opcode == LSM_SESSION_EVENT_DETECTION_STATUS_V2 ||
		opcode == LSM_SESSION_EVENT_DETECTION_STATUS_V3) {
		spin_lock_irqsave(&prtd->event_lock, flags);
		prtd->event_status = krealloc(prtd->event_status,
					sizeof(struct snd_lsm_event_status) +
					sizeof(struct snd_lsm_event_status_v3) +
					payload_size, GFP_ATOMIC);
		if (!prtd->event_status) {
			dev_err(rtd->dev, "%s: no memory for event status\n",
				__func__);
			return;
		}

		/*
		 * event status timestamp will be non-zero and valid if
		 * opcode is LSM_SESSION_EVENT_DETECTION_STATUS_V3
		 */
		prtd->event_status->timestamp_lsw = event_ts_lsw;
		prtd->event_status->timestamp_msw = event_ts_msw;
		prtd->event_status->status = status;
		prtd->event_status->payload_size = payload_size;

		if (likely(prtd->event_status)) {
			memcpy(prtd->event_status->payload,
			       &((uint8_t *)payload)[index],
@@ -769,10 +791,8 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
	struct snd_lsm_session_data session_data;
	int rc = 0;
	int xchg = 0;
	u32 size = 0;
	struct snd_pcm_runtime *runtime;
	struct lsm_priv *prtd;
	struct snd_lsm_event_status *user = arg;
	struct snd_lsm_detection_params det_params;
	uint8_t *confidence_level = NULL;
	bool poll_en;
@@ -954,6 +974,10 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
		break;

	case SNDRV_LSM_EVENT_STATUS:
	case SNDRV_LSM_EVENT_STATUS_V3: {
		uint32_t ts_lsw, ts_msw;
		uint16_t status = 0, payload_size = 0;

		dev_dbg(rtd->dev, "%s: Get event status\n", __func__);
		atomic_set(&prtd->event_wait_stop, 0);
		rc = wait_event_freezable(prtd->event_wait,
@@ -966,9 +990,12 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
			dev_dbg(rtd->dev, "%s: New event available %ld\n",
				__func__, prtd->event_avail);
			spin_lock_irqsave(&prtd->event_lock, flags);

			if (prtd->event_status) {
				size = sizeof(*(prtd->event_status)) +
				prtd->event_status->payload_size;
				payload_size = prtd->event_status->payload_size;
				ts_lsw = prtd->event_status->timestamp_lsw;
				ts_msw = prtd->event_status->timestamp_msw;
				status = prtd->event_status->status;
				spin_unlock_irqrestore(&prtd->event_lock,
						       flags);
			} else {
@@ -980,15 +1007,43 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
					__func__);
				break;
			}
			if (user->payload_size <
			    prtd->event_status->payload_size) {

			if (cmd == SNDRV_LSM_EVENT_STATUS) {
				struct snd_lsm_event_status *user = arg;

				if (user->payload_size < payload_size) {
					dev_dbg(rtd->dev,
						"%s: provided %d bytes isn't enough, needs %d bytes\n",
						__func__, user->payload_size,
					prtd->event_status->payload_size);
						payload_size);
					rc = -ENOMEM;
				} else {
					user->status = status;
					user->payload_size = payload_size;
					memcpy(user->payload,
						prtd->event_status->payload,
						payload_size);
				}
			} else {
				struct snd_lsm_event_status_v3 *user_v3 = arg;

				if (user_v3->payload_size < payload_size) {
					dev_dbg(rtd->dev,
						"%s: provided %d bytes isn't enough, needs %d bytes\n",
						__func__, user_v3->payload_size,
						payload_size);
					rc = -ENOMEM;
				} else {
				memcpy(user, prtd->event_status, size);
					user_v3->timestamp_lsw = ts_lsw;
					user_v3->timestamp_msw = ts_msw;
					user_v3->status = status;
					user_v3->payload_size = payload_size;
					memcpy(user_v3->payload,
						prtd->event_status->payload,
						payload_size);
				}
			}
			if (!rc) {
				if (prtd->lsm_client->lab_enable
					&& !prtd->lsm_client->lab_started
					&& prtd->event_status->status ==
@@ -1013,6 +1068,7 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
			rc = 0;
		}
		break;
	}

	case SNDRV_LSM_ABORT_EVENT:
		dev_dbg(rtd->dev, "%s: Aborting event status wait\n",
@@ -1127,6 +1183,37 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
		rc = q6lsm_set_port_connected(prtd->lsm_client);
		break;

	case SNDRV_LSM_SET_FWK_MODE_CONFIG: {
		u32 *mode = NULL;

		if (!arg) {
			dev_err(rtd->dev,
				"%s: Invalid param arg for ioctl %s session %d\n",
				__func__, "SNDRV_LSM_SET_FWK_MODE_CONFIG",
				prtd->lsm_client->session);
			rc = -EINVAL;
			break;
		}
		mode = (u32 *)arg;
		if (prtd->lsm_client->event_mode == *mode) {
			dev_dbg(rtd->dev,
				"%s: mode for %d already set to %d\n",
				__func__, prtd->lsm_client->session, *mode);
			rc = 0;
		} else {
			dev_dbg(rtd->dev, "%s: Event mode = %d\n",
				 __func__, *mode);
			rc = q6lsm_set_fwk_mode_cfg(prtd->lsm_client, *mode);
			if (!rc)
				prtd->lsm_client->event_mode = *mode;
			else
				dev_err(rtd->dev,
					"%s: set event mode failed %d\n",
					__func__, rc);
		}
		break;
	}

	default:
		dev_dbg(rtd->dev,
			"%s: Falling into default snd_lib_ioctl cmd 0x%x\n",
@@ -1151,6 +1238,14 @@ struct snd_lsm_event_status32 {
	u8 payload[0];
};

struct snd_lsm_event_status_v3_32 {
	u32 timestamp_lsw;
	u32 timestamp_msw;
	u16 status;
	u16 payload_size;
	u8 payload[0];
};

struct snd_lsm_sound_model_v2_32 {
	compat_uptr_t data;
	compat_uptr_t confidence_level;
@@ -1191,6 +1286,8 @@ enum {
		_IOW('U', 0x0A, struct snd_lsm_detection_params_32),
	SNDRV_LSM_SET_MODULE_PARAMS_32 =
		_IOW('U', 0x0B, struct snd_lsm_module_params_32),
	SNDRV_LSM_EVENT_STATUS_V3_32 =
		_IOW('U', 0x0F, struct snd_lsm_event_status_v3_32),
};

static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
@@ -1279,6 +1376,73 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
		break;
	}

	case SNDRV_LSM_EVENT_STATUS_V3_32: {
		struct snd_lsm_event_status_v3_32 userarg32, *user32 = NULL;
		struct snd_lsm_event_status_v3 *user = NULL;

		if (copy_from_user(&userarg32, arg, sizeof(userarg32))) {
			dev_err(rtd->dev, "%s: err copyuser ioctl %s\n",
				__func__, "SNDRV_LSM_EVENT_STATUS_V3_32");
			return -EFAULT;
		}

		if (userarg32.payload_size >
		    LISTEN_MAX_STATUS_PAYLOAD_SIZE) {
			pr_err("%s: payload_size %d is invalid, max allowed = %d\n",
				__func__, userarg32.payload_size,
				LISTEN_MAX_STATUS_PAYLOAD_SIZE);
			return -EINVAL;
		}

		size = sizeof(*user) + userarg32.payload_size;
		user = kmalloc(size, GFP_KERNEL);
		if (!user) {
			dev_err(rtd->dev,
				"%s: Allocation failed event status size %d\n",
				__func__, size);
			return -EFAULT;
		}
		cmd = SNDRV_LSM_EVENT_STATUS_V3;
		user->payload_size = userarg32.payload_size;
		err = msm_lsm_ioctl_shared(substream, cmd, user);

		/* Update size with actual payload size */
		size = sizeof(userarg32) + user->payload_size;
		if (!err && !access_ok(VERIFY_WRITE, arg, size)) {
			dev_err(rtd->dev,
				"%s: write verify failed size %d\n",
				__func__, size);
			err = -EFAULT;
		}
		if (!err) {
			user32 = kmalloc(size, GFP_KERNEL);
			if (!user32) {
				dev_err(rtd->dev,
					"%s: Allocation event user status size %d\n",
					__func__, size);
				err = -EFAULT;
			} else {
				user32->timestamp_lsw = user->timestamp_lsw;
				user32->timestamp_msw = user->timestamp_msw;
				user32->status = user->status;
				user32->payload_size = user->payload_size;
				memcpy(user32->payload,
				user->payload, user32->payload_size);
			}
		}
		if (!err && (copy_to_user(arg, user32, size))) {
			dev_err(rtd->dev, "%s: failed to copy payload %d",
				__func__, size);
			err = -EFAULT;
		}
		kfree(user);
		kfree(user32);
		if (err)
			dev_err(rtd->dev, "%s: lsmevent failed %d",
				__func__, err);
		break;
	}

	case SNDRV_LSM_REG_SND_MODEL_V2_32: {
		struct snd_lsm_sound_model_v2_32 snd_modelv232;
		struct snd_lsm_sound_model_v2 snd_modelv2;
@@ -1714,6 +1878,66 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
				"%s: lsmevent failed %d", __func__, err);
		return err;
	}

	case SNDRV_LSM_EVENT_STATUS_V3: {
		struct snd_lsm_event_status_v3 *user = NULL, userarg;

		dev_dbg(rtd->dev,
			"%s: SNDRV_LSM_EVENT_STATUS_V3\n", __func__);
		if (!arg) {
			dev_err(rtd->dev,
				"%s: Invalid params event_status_v3\n",
				__func__);
			return -EINVAL;
		}
		if (copy_from_user(&userarg, arg, sizeof(userarg))) {
			dev_err(rtd->dev,
				"%s: err copyuser event_status_v3\n",
				__func__);
			return -EFAULT;
		}

		if (userarg.payload_size >
		    LISTEN_MAX_STATUS_PAYLOAD_SIZE) {
			pr_err("%s: payload_size %d is invalid, max allowed = %d\n",
				__func__, userarg.payload_size,
				LISTEN_MAX_STATUS_PAYLOAD_SIZE);
			return -EINVAL;
		}

		size = sizeof(struct snd_lsm_event_status_v3) +
			userarg.payload_size;
		user = kmalloc(size, GFP_KERNEL);
		if (!user) {
			dev_err(rtd->dev,
				"%s: Allocation failed event status size %d\n",
				__func__, size);
			return -EFAULT;
		}
		user->payload_size = userarg.payload_size;
		err = msm_lsm_ioctl_shared(substream, cmd, user);

		/* Update size with actual payload size */
		size = sizeof(*user) + user->payload_size;
		if (!err && !access_ok(VERIFY_WRITE, arg, size)) {
			dev_err(rtd->dev,
				"%s: write verify failed size %d\n",
				__func__, size);
			err = -EFAULT;
		}
		if (!err && (copy_to_user(arg, user, size))) {
			dev_err(rtd->dev,
				"%s: failed to copy payload %d",
				__func__, size);
			err = -EFAULT;
		}
		kfree(user);
		if (err)
			dev_err(rtd->dev,
				"%s: lsm_event_v3 failed %d", __func__, err);
		break;
	}

	default:
		err = msm_lsm_ioctl_shared(substream, cmd, arg);
	break;
@@ -1784,6 +2008,7 @@ static int msm_lsm_open(struct snd_pcm_substream *substream)
	prtd->lsm_client->session_state = IDLE;
	prtd->lsm_client->poll_enable = true;
	prtd->lsm_client->perf_mode = 0;
	prtd->lsm_client->event_mode = LSM_EVENT_NON_TIME_STAMP_MODE;

	return 0;
}
+48 −0
Original line number Diff line number Diff line
@@ -864,6 +864,54 @@ int q6lsm_polling_enable(struct lsm_client *client, bool poll_en)
	return rc;
}

int q6lsm_set_fwk_mode_cfg(struct lsm_client *client,
			   uint32_t event_mode)
{
	int rc = 0;
	struct lsm_cmd_set_fwk_mode_cfg cmd;
	struct lsm_module_param_ids fwk_mode_cfg_ids;
	struct apr_hdr  *msg_hdr;
	struct lsm_param_fwk_mode_cfg *fwk_mode_cfg;
	u32 data_payload_size, param_size, set_param_opcode;

	if (client->use_topology) {
		set_param_opcode = LSM_SESSION_CMD_SET_PARAMS_V2;
		fwk_mode_cfg_ids.module_id = LSM_MODULE_ID_FRAMEWORK;
		fwk_mode_cfg_ids.param_id = LSM_PARAM_ID_FWK_MODE_CONFIG;
	} else {
		pr_debug("%s: Ignore sending event mode\n", __func__);
		return rc;
	}

	msg_hdr = &cmd.msg_hdr;
	q6lsm_add_hdr(client, msg_hdr,
		      sizeof(struct lsm_cmd_set_fwk_mode_cfg), true);
	msg_hdr->opcode = set_param_opcode;
	data_payload_size = sizeof(struct lsm_cmd_set_fwk_mode_cfg) -
			    sizeof(struct apr_hdr) -
			    sizeof(struct lsm_set_params_hdr);
	q6lsm_set_param_hdr_info(&cmd.params_hdr,
				 data_payload_size, 0, 0, 0);
	fwk_mode_cfg = &cmd.fwk_mode_cfg;

	param_size = (sizeof(struct lsm_param_fwk_mode_cfg) -
		      sizeof(fwk_mode_cfg->common));
	q6lsm_set_param_common(&fwk_mode_cfg->common,
			       &fwk_mode_cfg_ids, param_size,
			       set_param_opcode);

	fwk_mode_cfg->minor_version = QLSM_PARAM_ID_MINOR_VERSION;
	fwk_mode_cfg->mode = event_mode;
	pr_debug("%s: mode = %d\n", __func__, fwk_mode_cfg->mode);

	rc = q6lsm_apr_send_pkt(client, client->apr,
				&cmd, true, NULL);
	if (rc)
		pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
		       __func__, msg_hdr->opcode, rc);
	return rc;
}

int q6lsm_set_data(struct lsm_client *client,
			   enum lsm_detection_mode mode,
			   bool detectfailure)