/* This computes linear mapping device volume. */
s32 qdsp6_volume_mapping(u32 device_id, s32 percentage)
{
	s32 max_gain = 0;
	s32 min_gain = 0;
	u32 tmp_device_id = qdsp6_volume_device_id_mapping(device_id);

	if (tmp_device_id == INT_CAD_HW_DEVICE_ID_INVALID) {
		pr_err("%s: invalid device\n", __func__);
		return 0xFFFFFFFF;
	}

	if (percentage < 0 || percentage > 100) {
		pr_err("%s: invalid percentage\n", __func__);
		return 0xFFFFFFFF;
	}

	max_gain = qdsp6_volume_cache_tbl[device_id].max_gain;
	min_gain = qdsp6_volume_cache_tbl[device_id].min_gain;

	return min_gain + (((max_gain - min_gain) * percentage) / 100);
}
s32 qdsp6_volume_ioctl(s32 session_id, u32 cmd_code,
	void *cmd_buf, u32 cmd_len)
{
	enum cad_int_device_id device_id = INT_CAD_HW_DEVICE_ID_INVALID;
	struct cad_filter_struct *vol_flt = NULL;
	struct cad_flt_cfg_dev_vol *dev_vol_buf = NULL;
	struct cad_flt_cfg_strm_vol *stream_vol_buf = NULL;
	struct cad_flt_cfg_dev_mute *dev_mute_buf = NULL;
	struct cad_flt_cfg_strm_mute *stream_mute_buf = NULL;

	struct adsp_audio_set_device_volume *q6_set_dev_vol = NULL;
	struct adsp_audio_set_stream_volume *q6_set_strm_vol = NULL;
	struct adsp_audio_set_device_mute *q6_set_dev_mute = NULL;
	struct adsp_audio_set_stream_mute *q6_set_strm_mute = NULL;

	int rc = CAD_RES_SUCCESS;
	s32 device_volume = 0;
	s32 rpc_cmd_code = 0;
	u8 *rpc_cmd_buf = NULL;
	u32 rpc_cmd_buf_len = 0;
	struct adsp_audio_event event_payload;

	struct adsp_audio_set_device_volume *q6_set_dev_vol1 = NULL;
	struct adsp_audio_set_stream_volume *q6_set_strm_vol1 = NULL;
	struct adsp_audio_set_device_mute *q6_set_dev_mute1 = NULL;
	struct adsp_audio_set_stream_mute *q6_set_strm_mute1 = NULL;

	s32 rpc_cmd_code1 = 0;
	u8 *rpc_cmd_buf1 = NULL;
	u32 rpc_cmd_buf_len1 = 0;
	struct adsp_audio_event event_payload1;


	memset(&event_payload, 0, sizeof(struct adsp_audio_event));
	memset(&event_payload1, 0, sizeof(struct adsp_audio_event));
	/* Ensure session_id is valid. */
	if (session_id < 1 || session_id >= CAD_MAX_SESSION)
		return CAD_RES_FAILURE;

	/* Not handle request other than the following two. */
	/* Just silently succeed unrecognized IOCTLs. */
	if (cmd_code != CAD_IOCTL_CMD_SET_STREAM_FILTER_CONFIG &&
		cmd_code != CAD_IOCTL_CMD_SET_DEVICE_FILTER_CONFIG &&
		cmd_code != CAD_IOCTL_CMD_STREAM_START)
		return CAD_RES_SUCCESS;

	/* Defensive programming. */
	if ((cmd_buf == NULL
		|| cmd_len != sizeof(struct cad_filter_struct))
		&& cmd_code != CAD_IOCTL_CMD_STREAM_START) {
		D("%s: invalid params\n", __func__);
		return CAD_RES_FAILURE;
	}

	/* Do not handle stream_start for device control session. */
	if (cmd_code == CAD_IOCTL_CMD_STREAM_START &&
		ardsession[session_id]->session_type == DEVICE_CTRL_TYPE) {
		D("%s: not handling for device control type\n", __func__);
		return CAD_RES_SUCCESS;
	}

	/* Handle stream start. */
	if (cmd_code == CAD_IOCTL_CMD_STREAM_START) {
		if (ardsession[session_id]->sess_open_info->cad_stream.app_type
				== CAD_STREAM_APP_VOICE) {
			D("%s: Do not handle voice session.\n", __func__);
			return CAD_RES_SUCCESS;
		}

		q6_set_strm_mute1 = kmalloc(
			sizeof(struct adsp_audio_set_stream_mute),
			GFP_KERNEL);
		if (!q6_set_strm_mute1)
			return CAD_RES_FAILURE;

		memset(q6_set_strm_mute1, 0,
			sizeof(struct adsp_audio_set_stream_mute));
		/* 2. Assign values to command buffer. */
		if (stream_volume_cache == CAD_STREAM_MIN_GAIN)
			q6_set_strm_mute1->mute = 1;
		else
			q6_set_strm_mute1->mute = 0;

		rpc_cmd_buf1 = (u8 *)q6_set_strm_mute1;
		rpc_cmd_buf_len1 = sizeof(struct adsp_audio_set_stream_mute);
		rpc_cmd_code1 = ADSP_AUDIO_IOCTL_CMD_SET_STREAM_MUTE;
		/* 3. Send command to Q6. */

		if (ardsession[session_id]->sess_open_info->cad_open.op_code
				== CAD_OPEN_OP_WRITE) {
			/* Only issue stream commands for Rx path. */
			rc = cad_rpc_ioctl(
				session_id,
				1,
				rpc_cmd_code1,
				rpc_cmd_buf1,
				rpc_cmd_buf_len1,
				&event_payload1);
			if (rc != CAD_RES_SUCCESS) {
				pr_err("%s: cad_rpc_ioctl() failure\n",
					__func__);
				return rc;
			}
		}

		if (stream_volume_cache != CAD_STREAM_MIN_GAIN) {
			q6_set_strm_vol1 = kmalloc(
				sizeof(struct adsp_audio_set_stream_volume),
				GFP_KERNEL);
			if (!q6_set_strm_vol1)
				return CAD_RES_FAILURE;

			/* 2. Assign values to command buffer. */
			q6_set_strm_vol1->volume = stream_volume_cache;
			rpc_cmd_buf1 = (u8 *)q6_set_strm_vol1;
			rpc_cmd_buf_len1 =
				sizeof(struct adsp_audio_set_stream_volume);
			rpc_cmd_code1 = ADSP_AUDIO_IOCTL_CMD_SET_STREAM_VOL;
			if (ardsession[session_id]->sess_open_info->
				cad_open.op_code == CAD_OPEN_OP_WRITE) {
				/* Only issue stream commands for Rx path. */
				rc = cad_rpc_ioctl(
					session_id,
					1,
					rpc_cmd_code1,
					rpc_cmd_buf1,
					rpc_cmd_buf_len1,
					&event_payload1);
				if (rc != CAD_RES_SUCCESS) {
					pr_err("%s: cad_rpc_ioctl() failure\n",
						__func__);
					return rc;
				}
			}
		}

		q6_set_dev_mute1 = kmalloc(
			sizeof(struct adsp_audio_set_device_mute), GFP_KERNEL);
		if (!q6_set_dev_mute1) {
			rc = CAD_RES_FAILURE;
			goto done;
		}

		memset(q6_set_dev_mute1, 0,
			sizeof(struct adsp_audio_set_device_mute));

		/* Send Device Volume during stream start. */
		if (ardsession[session_id]->sess_open_info->cad_open.op_code
				== CAD_OPEN_OP_READ) {
			device_id = ard_state.def_tx_device;

			if (device_id == INT_CAD_HW_DEVICE_ID_INVALID) {
				rc = CAD_RES_FAILURE;
				pr_err("%s: invalid device id %d\n", __func__,
					ard_state.def_tx_device);
				goto done;
			}
			q6_set_dev_mute1->path = CAD_TX_DEVICE;
		} else if (ardsession[session_id]->sess_open_info->
				cad_open.op_code == CAD_OPEN_OP_WRITE) {
			device_id = ard_state.def_rx_device;

			if (device_id == INT_CAD_HW_DEVICE_ID_INVALID) {
				rc = CAD_RES_FAILURE;
				pr_err("%s: invalid device id %d\n", __func__,
						ard_state.def_rx_device);
				goto done;
			}
			q6_set_dev_mute1->path = CAD_RX_DEVICE;
		}

		/* 2. Assign values to command buffer. */
		q6_set_dev_mute1->device = q6_device_id_mapping(device_id);

		device_id = qdsp6_volume_device_id_mapping(device_id);

		if (qdsp6_volume_cache_tbl[device_id].mute == 1)
			q6_set_dev_mute1->mute = 1;
		else
			q6_set_dev_mute1->mute = 0;

		rpc_cmd_buf1 = (u8 *)q6_set_dev_mute1;
		rpc_cmd_buf_len1 = sizeof(struct adsp_audio_set_device_mute);
		rpc_cmd_code1 = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE;

		rc = cad_rpc_ioctl(
			audio_ctrl_handle,
			1,
			rpc_cmd_code1,
			rpc_cmd_buf1,
			rpc_cmd_buf_len1,
			&event_payload1);
		if (rc != CAD_RES_SUCCESS) {
			pr_err("%s: cad_rpc_ioctl() failure\n",
				__func__);
			return rc;
		}

		if (qdsp6_volume_cache_tbl[device_id].mute == 0) {

			q6_set_dev_vol1 = kmalloc(
				sizeof(struct adsp_audio_set_device_volume),
				GFP_KERNEL);
			if (!q6_set_dev_vol1)
				return CAD_RES_FAILURE;

			memset(q6_set_dev_vol1, 0,
				sizeof(struct adsp_audio_set_device_volume));

			if (qdsp6_volume_cache_tbl[device_id].
						valid_current_volume == 1) {
				q6_set_dev_vol1->volume =
					qdsp6_volume_cache_tbl[device_id].
							current_volume;
				D("%s: current_volume is %d\n", __func__,
						q6_set_dev_vol1->volume);
			} else {
				q6_set_dev_vol1->volume =
					qdsp6_volume_cache_tbl[device_id].
							default_volume;
				D("%s: current_volume is %d (default)\n",
					__func__, q6_set_dev_vol1->volume);
			}

			q6_set_dev_vol1->path = q6_set_dev_mute1->path;
			q6_set_dev_vol1->device = q6_set_dev_mute1->device;
			rpc_cmd_buf1 = (u8 *)q6_set_dev_vol1;
			rpc_cmd_buf_len1 =
				sizeof(struct adsp_audio_set_device_volume);
			rpc_cmd_code1 = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL;

			rc = cad_rpc_ioctl(
				audio_ctrl_handle,
				1,
				rpc_cmd_code1,
				rpc_cmd_buf1,
				rpc_cmd_buf_len1,
				&event_payload1);
			if (rc != CAD_RES_SUCCESS) {
				pr_err("%s: cad_rpc_ioctl() failure\n",
					__func__);
				return rc;
			}
		}

		rc = CAD_RES_SUCCESS;
		goto done;
	}

	if ((cmd_buf == NULL) || (cmd_len !=
			sizeof(struct cad_filter_struct))) {
		pr_err("%s: invalid ioctl params\n", __func__);
		rc = CAD_RES_FAILURE;
		goto done;
	}

	vol_flt = (struct cad_filter_struct *)cmd_buf;

	if (vol_flt->filter_type != CAD_DEVICE_FILTER_TYPE_VOL) {
		D("%s: not volume filter type\n", __func__);
		rc = CAD_RES_SUCCESS;
		goto done;
	}

	/* Find the appropriate command type. */
	if (cmd_code == CAD_IOCTL_CMD_SET_DEVICE_FILTER_CONFIG
		&& vol_flt->cmd == CAD_FILTER_CONFIG_DEVICE_VOLUME
		&& vol_flt->format_block_len ==
			sizeof(struct cad_flt_cfg_dev_vol))
		dev_vol_buf =
			(struct cad_flt_cfg_dev_vol *)
					vol_flt->format_block;
	else if (CAD_IOCTL_CMD_SET_DEVICE_FILTER_CONFIG == cmd_code
		&& vol_flt->cmd == CAD_FILTER_CONFIG_DEVICE_MUTE
		&& vol_flt->format_block_len ==
			sizeof(struct cad_flt_cfg_dev_mute))
		dev_mute_buf = (struct cad_flt_cfg_dev_mute *)
						vol_flt->format_block;

	/* stream session */
	else if (cmd_code == CAD_IOCTL_CMD_SET_STREAM_FILTER_CONFIG
		&& vol_flt->cmd == CAD_FILTER_CONFIG_STREAM_VOLUME
		&& vol_flt->format_block_len ==
			sizeof(struct cad_flt_cfg_strm_vol))
		stream_vol_buf = (struct cad_flt_cfg_strm_vol *)(
					vol_flt->format_block);

	else if (cmd_code == CAD_IOCTL_CMD_SET_STREAM_FILTER_CONFIG
		&& vol_flt->cmd == CAD_FILTER_CONFIG_STREAM_MUTE
		&& vol_flt->format_block_len ==
			sizeof(struct cad_flt_cfg_strm_mute))
		stream_mute_buf = (struct cad_flt_cfg_strm_mute *)
						(vol_flt->format_block);

	else {
		pr_err("CAD:VOL: Error: wrong type id.\n");
		return CAD_RES_FAILURE;
	}

	/* Handle volume control command. */
	switch (vol_flt->cmd) {
	case CAD_FILTER_CONFIG_DEVICE_VOLUME:
		D("CAD:VOL: Device Volume\n");

		if (dev_vol_buf->device_id == 0 ||
			dev_vol_buf->device_id > CAD_HW_DEVICE_ID_MAX_NUM) {
			pr_err("%s: invalid device id %d.\n",
					__func__, dev_vol_buf->device_id);
			rc = CAD_RES_FAILURE;
			goto done;
		}

		if (dev_vol_buf->device_id == CAD_HW_DEVICE_ID_DEFAULT_TX)
			dev_vol_buf->device_id = ard_state.def_tx_device;
		else if (dev_vol_buf->device_id == CAD_HW_DEVICE_ID_DEFAULT_RX)
			dev_vol_buf->device_id = ard_state.def_rx_device;
		else
			; /* Do nothing. */

		if (ardsession[session_id]->sess_open_info->cad_open.op_code
				== CAD_OPEN_OP_READ) {
			if (dev_vol_buf->device_id !=
					ard_state.def_tx_device) {
				pr_err("%s: %d is not current device id.\n",
					__func__, dev_vol_buf->device_id);
				rc = CAD_RES_FAILURE;
				goto done;
			}
		} else if (ardsession[session_id]->sess_open_info->
				cad_open.op_code == CAD_OPEN_OP_WRITE) {
			if (dev_vol_buf->device_id !=
					ard_state.def_rx_device) {
				pr_err("%s: %d is not current device id.\n",
					__func__, dev_vol_buf->device_id);
				rc = CAD_RES_FAILURE;
				goto done;
			}
		}

		/* For volume != 0%: send unmute command. */
		if (dev_vol_buf->volume != 0) {
			/* Construct QDSP6 device mute command. */
			/* 1. Allocate memory for command buffer. */
			q6_set_dev_mute = kmalloc(
				sizeof(struct adsp_audio_set_device_mute),
				GFP_KERNEL);
			if (!q6_set_dev_mute)
				return CAD_RES_FAILURE;

			memset(q6_set_dev_mute, 0,
				sizeof(struct adsp_audio_set_device_mute));
			/* 2. Assign values to command buffer. */
			q6_set_dev_mute->device =
				q6_device_id_mapping(dev_vol_buf->device_id);
			q6_set_dev_mute->path = dev_vol_buf->path;
			q6_set_dev_mute->mute = 0;
			rpc_cmd_buf = (u8 *)q6_set_dev_mute;
			rpc_cmd_buf_len =
				sizeof(struct adsp_audio_set_device_mute);
			rpc_cmd_code = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE;
			/* 3. Send command to Q6. */
			rc = cad_rpc_ioctl(
				session_id,
				1,
				rpc_cmd_code,
				rpc_cmd_buf,
				rpc_cmd_buf_len,
				&event_payload);
			if (rc != CAD_RES_SUCCESS) {
				pr_err("%s: cad_rpc_ioctl() failure\n",
					__func__);
				return rc;
			}

		}

		/* Map the device volume to QDSP6. */
		device_volume = qdsp6_volume_mapping(
			dev_vol_buf->device_id,
			dev_vol_buf->volume);

		/* Cache the device volume. */
		device_id = qdsp6_volume_device_id_mapping(
				dev_vol_buf->device_id);
		qdsp6_volume_cache_tbl[device_id]
			.current_volume = device_volume;
		qdsp6_volume_cache_tbl[device_id]
			.valid_current_volume = 1;
		qdsp6_volume_cache_tbl[device_id]
			.mute = 0;

		/* Construct QDSP6 device volume command:	*/
		/* 1. Allocate memory for command buffer.	*/
		q6_set_dev_vol = kmalloc(
			sizeof(struct cad_flt_cfg_dev_vol),
			GFP_KERNEL);
		if (!q6_set_dev_vol)
			return CAD_RES_FAILURE;

		memset(q6_set_dev_vol, 0,
			sizeof(struct adsp_audio_set_device_volume));

		/* 2. Assign values to command buffer. */
		q6_set_dev_vol->device =
			q6_device_id_mapping(dev_vol_buf->device_id);
		q6_set_dev_vol->path = dev_vol_buf->path;
		q6_set_dev_vol->volume = device_volume;
		rpc_cmd_buf = (u8 *)q6_set_dev_vol;
		rpc_cmd_buf_len =
			sizeof(struct adsp_audio_set_device_volume);
		rpc_cmd_code = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL;

		/* HACK: for volume = 0%: send mute command instead. */
		if (dev_vol_buf->volume == 0) {
			/* Construct QDSP6 device mute command. */
			/* 1. Allocate memory for command buffer. */
			q6_set_dev_mute = kmalloc(
				sizeof(struct adsp_audio_set_device_mute),
				GFP_KERNEL);
			if (!q6_set_dev_mute)
				return CAD_RES_FAILURE;

			memset(q6_set_dev_mute, 0,
				sizeof(struct adsp_audio_set_device_mute));
			/* 2. Assign values to command buffer. */
			q6_set_dev_mute->device = q6_set_dev_vol->device;
			q6_set_dev_mute->path = q6_set_dev_vol->path;
			q6_set_dev_mute->mute = 1; /* mute */
			rpc_cmd_buf = (u8 *)q6_set_dev_mute;
			rpc_cmd_buf_len =
				sizeof(struct adsp_audio_set_device_mute);
			rpc_cmd_code = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE;
		}

		break;
	case CAD_FILTER_CONFIG_DEVICE_MUTE:
		D("CAD:VOL: Device Mute\n");

		device_id = qdsp6_volume_device_id_mapping(
				dev_mute_buf->device_id);
		qdsp6_volume_cache_tbl[device_id].mute = dev_mute_buf->mute;

		/* Construct QDSP6 device mute command. */
		/* 1. Allocate memory for command buffer. */
		q6_set_dev_mute = kmalloc(
			sizeof(struct adsp_audio_set_device_mute),
			GFP_KERNEL);
		if (!q6_set_dev_mute)
			return CAD_RES_FAILURE;

		memset(q6_set_dev_mute, 0,
			sizeof(struct adsp_audio_set_device_mute));
		/* 2. Assign values to command buffer. */
		q6_set_dev_mute->device =
			q6_device_id_mapping(dev_mute_buf->device_id);
		q6_set_dev_mute->path = dev_mute_buf->path;
		q6_set_dev_mute->mute = dev_mute_buf->mute;
		rpc_cmd_buf = (u8 *)q6_set_dev_mute;
		rpc_cmd_buf_len =
			sizeof(struct adsp_audio_set_device_mute);
		rpc_cmd_code = ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE;

		break;
	case CAD_FILTER_CONFIG_STREAM_VOLUME:
		D("CAD:VOL: Stream Volume\n");

		stream_volume_cache = stream_vol_buf->volume;

		if (ardsession[session_id]->active != ARD_TRUE) {
			rc = CAD_RES_SUCCESS;
			D("not active session, cached stream volume.\n");
			goto done;
		}

		/* For volume != min: send unmute command. */
		if (stream_vol_buf->volume != CAD_STREAM_MIN_GAIN) {
			/* Construct QDSP6 stream mute command. */
			/* 1. Allocate memory for command buffer. */
			q6_set_strm_mute = kmalloc(
				sizeof(struct adsp_audio_set_stream_mute),
				GFP_KERNEL);
			if (!q6_set_strm_mute)
				return CAD_RES_FAILURE;

			/* 2. Assign values to command buffer.	*/
			q6_set_strm_mute->mute = 0;
			rpc_cmd_buf = (u8 *)q6_set_strm_mute;
			rpc_cmd_buf_len =
				sizeof(struct adsp_audio_set_stream_mute);
			rpc_cmd_code = ADSP_AUDIO_IOCTL_CMD_SET_STREAM_MUTE;
			/* 3. Send command to Q6. */
			rc = cad_rpc_ioctl(session_id,
					     1,
					     rpc_cmd_code,
					     rpc_cmd_buf,
					     rpc_cmd_buf_len,
					     &event_payload);
			if (rc != CAD_RES_SUCCESS) {
				pr_err("%s: cad_rpc_ioctl() failure\n",
					__func__);
				return rc;
			}
		}

		/* Construct QDSP6 stream volume command. */
		/* 1. Allocate memory for command buffer. */
		q6_set_strm_vol = kmalloc(
			sizeof(struct adsp_audio_set_stream_volume),
			GFP_KERNEL);
		if (!q6_set_strm_vol)
			return CAD_RES_FAILURE;

		/* 2. Assign values to command buffer. */
		q6_set_strm_vol->volume = stream_vol_buf->volume;
		rpc_cmd_buf = (u8 *)q6_set_strm_vol;
		rpc_cmd_buf_len = sizeof(struct adsp_audio_set_stream_volume);
		rpc_cmd_code = ADSP_AUDIO_IOCTL_CMD_SET_STREAM_VOL;

		/* For volume = min: send mute command instead. */
		if (stream_vol_buf->volume == CAD_STREAM_MIN_GAIN) {
			/* Construct QDSP6 stream mute command. */
			/* 1. Allocate memory for command buffer. */
			q6_set_strm_mute = kmalloc(
					sizeof(
					struct adsp_audio_set_stream_mute),
					GFP_KERNEL);

			if (!q6_set_strm_mute)
				return CAD_RES_FAILURE;

			/* 2. Assign values to command buffer. */
			q6_set_strm_mute->mute = 1;
			rpc_cmd_buf = (u8 *)q6_set_strm_mute;
			rpc_cmd_buf_len =
				sizeof(struct adsp_audio_set_stream_mute);
			rpc_cmd_code = ADSP_AUDIO_IOCTL_CMD_SET_STREAM_MUTE;
		}

		break;
	case CAD_FILTER_CONFIG_STREAM_MUTE:
		D("CAD:VOL: Stream Mute\n");

		/* Construct QDSP6 stream mute command. */
		/* 1. Allocate memory for command buffer. */
		q6_set_strm_mute = kmalloc(
					sizeof(
					struct adsp_audio_set_stream_mute),
					GFP_KERNEL);
		if (!q6_set_strm_mute)
			return CAD_RES_FAILURE;

		/* 2. Assign values to command buffer. */
		q6_set_strm_mute->mute = stream_mute_buf->mute;
		rpc_cmd_buf = (u8 *)q6_set_strm_mute;
		rpc_cmd_buf_len = sizeof(struct adsp_audio_set_stream_mute);
		rpc_cmd_code = ADSP_AUDIO_IOCTL_CMD_SET_STREAM_MUTE;

		break;
	default:
		/* Just return without error. */
		return CAD_RES_SUCCESS;
	}

	/* Always send device/stream volume command to Q6 for now. */
	rc = cad_rpc_ioctl(
			session_id,
			1,
			rpc_cmd_code,
			rpc_cmd_buf,
			rpc_cmd_buf_len,
			&event_payload);
	if (rc != CAD_RES_SUCCESS)
		pr_err("%s: cad_rpc_ioctl() failure\n", __func__);

done:
	D("%s: ioctl() processed.\n", __func__);

	kfree(q6_set_dev_vol);
	kfree(q6_set_strm_vol);
	kfree(q6_set_dev_mute);
	kfree(q6_set_strm_mute);
	kfree(q6_set_dev_vol1);
	kfree(q6_set_strm_vol1);
	kfree(q6_set_dev_mute1);
	kfree(q6_set_strm_mute1);

	return rc;
}
Esempio n. 3
0
int cad_apply_cached_vol_on_dev(u32 device_id)
{
	struct adsp_audio_set_dev_volume_command *q6_set_dev_vol;
	struct adsp_audio_set_dev_mute_command	*q6_set_dev_mute;
	union adsp_audio_event event_payload;
	u32 path = CAD_RX_DEVICE;
	u8 *rpc_cmd_buf = NULL;
	u32 rpc_cmd_buf_len = 0;
	int int_dev_id = qdsp6_volume_device_id_mapping(device_id);
	s32 rc = CAD_RES_SUCCESS;

	D("%s: device_id = %d\n", __func__, device_id);

	if (int_dev_id == INT_CAD_HW_DEVICE_ID_INVALID) {
		pr_err("%s: bad device_id (%d)\n", __func__, device_id);
		return CAD_RES_FAILURE;
	}

	if (qdsp6_volume_cache_tbl[int_dev_id].valid_current_volume == 1) {
		q6_set_dev_vol = kmalloc(sizeof(*q6_set_dev_vol), GFP_KERNEL);
		if (!q6_set_dev_vol)
			return CAD_RES_FAILURE;

		memset(q6_set_dev_vol, 0, sizeof(*q6_set_dev_vol));

		q6_set_dev_mute = kmalloc(
			sizeof(*q6_set_dev_mute), GFP_KERNEL);
		if (!q6_set_dev_mute) {
			kfree(q6_set_dev_vol);
			return CAD_RES_FAILURE;
		}

		memset(q6_set_dev_mute, 0, sizeof(*q6_set_dev_mute));

		if (ardsession[audio_ctrl_handle]->sess_open_info->
					cad_open.op_code == CAD_OPEN_OP_READ)
			path = CAD_TX_DEVICE;
		else if (ardsession[audio_ctrl_handle]->sess_open_info->
				cad_open.op_code == CAD_OPEN_OP_WRITE)
			path = CAD_RX_DEVICE;

		q6_set_dev_vol->volume =
			qdsp6_volume_cache_tbl[int_dev_id].current_volume;
		q6_set_dev_vol->device_id = q6_device_id_mapping(device_id);
		q6_set_dev_vol->path = path;

		q6_set_dev_vol->cmd.op_code =
			ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_VOL;
		q6_set_dev_vol->cmd.response_type =
			ADSP_AUDIO_RESPONSE_COMMAND;
		rpc_cmd_buf = (u8 *)q6_set_dev_vol;
		rpc_cmd_buf_len = sizeof(*q6_set_dev_vol);

		rc = cad_rpc_control(audio_ctrl_handle,
			ardsession[audio_ctrl_handle]->group_id,
			(void *)rpc_cmd_buf,
			rpc_cmd_buf_len,
			&event_payload);

		if (rc != CAD_RES_SUCCESS)
			pr_err("%s: cad_rpc_control() failure\n", __func__);


		if ((qdsp6_volume_cache_tbl[int_dev_id].mute == 1) ||
			(qdsp6_volume_cache_tbl[int_dev_id].current_volume ==
				qdsp6_volume_cache_tbl[int_dev_id].min_gain))
			q6_set_dev_mute->mute = 1;
		else
			q6_set_dev_mute->mute = 0;

		q6_set_dev_mute->device_id = q6_device_id_mapping(device_id);
		q6_set_dev_mute->path = path;

		rpc_cmd_buf = (u8 *)q6_set_dev_mute;
		rpc_cmd_buf_len = sizeof(*q6_set_dev_mute);

		q6_set_dev_mute->cmd.op_code =
			ADSP_AUDIO_IOCTL_CMD_SET_DEVICE_MUTE;
		q6_set_dev_mute->cmd.response_type =
			ADSP_AUDIO_RESPONSE_COMMAND;

		rc = cad_rpc_control(audio_ctrl_handle,
				ardsession[audio_ctrl_handle]->group_id,
				(void *)rpc_cmd_buf,
				rpc_cmd_buf_len,
				&event_payload);

		kfree(q6_set_dev_vol);
		kfree(q6_set_dev_mute);
	}

	return rc;
}