Initial Contribution
msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142
Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
diff --git a/sound/soc/msm/qdsp6/Makefile b/sound/soc/msm/qdsp6/Makefile
new file mode 100644
index 0000000..5fd69cc
--- /dev/null
+++ b/sound/soc/msm/qdsp6/Makefile
@@ -0,0 +1 @@
+obj-y := q6asm.o q6adm.o q6afe.o q6voice.o
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
new file mode 100644
index 0000000..65d1fbc
--- /dev/null
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -0,0 +1,804 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+#include <linux/bitops.h>
+#include <mach/qdsp6v2/rtac.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+#include <sound/apr_audio.h>
+#include <sound/q6afe.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+
+#define TIMEOUT_MS 1000
+#define AUDIO_RX 0x0
+#define AUDIO_TX 0x1
+#define ASM_MAX_SESSION 0x8 /* To do: define in a header */
+#define RESET_COPP_ID 99
+#define INVALID_COPP_ID 0xFF
+
+struct adm_ctl {
+ void *apr;
+ atomic_t copp_id[AFE_MAX_PORTS];
+ atomic_t copp_cnt[AFE_MAX_PORTS];
+ atomic_t copp_stat[AFE_MAX_PORTS];
+ unsigned long sessions[AFE_MAX_PORTS];
+ wait_queue_head_t wait;
+};
+
+static struct adm_ctl this_adm;
+
+static int32_t adm_callback(struct apr_client_data *data, void *priv)
+{
+ uint32_t *payload;
+ int i, index;
+ payload = data->payload;
+
+ if (data->opcode == RESET_EVENTS) {
+ pr_debug("adm_callback: Reset event is received: %d %d apr[%p]\n",
+ data->reset_event, data->reset_proc,
+ this_adm.apr);
+ if (this_adm.apr) {
+ apr_reset(this_adm.apr);
+ for (i = 0; i < AFE_MAX_PORTS; i++) {
+ atomic_set(&this_adm.copp_id[i],
+ RESET_COPP_ID);
+ atomic_set(&this_adm.copp_cnt[i], 0);
+ atomic_set(&this_adm.copp_stat[i], 0);
+ }
+ this_adm.apr = NULL;
+ }
+ return 0;
+ }
+
+ pr_debug("%s: code = 0x%x %x %x size = %d\n", __func__,
+ data->opcode, payload[0], payload[1],
+ data->payload_size);
+
+ if (data->payload_size) {
+ index = afe_get_port_index(data->token);
+ pr_debug("%s: Port ID %d, index %d\n", __func__,
+ data->token, index);
+
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ pr_debug("APR_BASIC_RSP_RESULT\n");
+ switch (payload[0]) {
+ case ADM_CMD_SET_PARAMS:
+#ifdef CONFIG_MSM8X60_RTAC
+ if (rtac_make_adm_callback(payload,
+ data->payload_size))
+ break;
+#endif
+ case ADM_CMD_COPP_CLOSE:
+ case ADM_CMD_MEMORY_MAP:
+ case ADM_CMD_MEMORY_UNMAP:
+ case ADM_CMD_MEMORY_MAP_REGIONS:
+ case ADM_CMD_MEMORY_UNMAP_REGIONS:
+ case ADM_CMD_MATRIX_MAP_ROUTINGS:
+ pr_debug("ADM_CMD_MATRIX_MAP_ROUTINGS\n");
+ atomic_set(&this_adm.copp_stat[index], 1);
+ wake_up(&this_adm.wait);
+ break;
+ default:
+ pr_err("%s: Unknown Cmd: 0x%x\n", __func__,
+ payload[0]);
+ break;
+ }
+ return 0;
+ }
+
+ switch (data->opcode) {
+ case ADM_CMDRSP_COPP_OPEN: {
+ struct adm_copp_open_respond *open = data->payload;
+ if (open->copp_id == INVALID_COPP_ID) {
+ pr_err("%s: invalid coppid rxed %d\n",
+ __func__, open->copp_id);
+ atomic_set(&this_adm.copp_stat[index], 1);
+ wake_up(&this_adm.wait);
+ break;
+ }
+ atomic_set(&this_adm.copp_id[index], open->copp_id);
+ atomic_set(&this_adm.copp_stat[index], 1);
+ pr_debug("%s: coppid rxed=%d\n", __func__,
+ open->copp_id);
+ wake_up(&this_adm.wait);
+ }
+ break;
+#ifdef CONFIG_MSM8X60_RTAC
+ case ADM_CMDRSP_GET_PARAMS:
+ pr_debug("ADM_CMDRSP_GET_PARAMS\n");
+ rtac_make_adm_callback(payload,
+ data->payload_size);
+ break;
+#endif
+ default:
+ pr_err("%s: Unknown cmd:0x%x\n", __func__,
+ data->opcode);
+ break;
+ }
+ }
+ return 0;
+}
+
+void send_cal(int port_id, struct acdb_cal_block *aud_cal)
+{
+ s32 result;
+ struct adm_set_params_command adm_params;
+ int index = afe_get_port_index(port_id);
+
+ pr_debug("%s: Port id %d, index %d\n", __func__, port_id, index);
+
+ if (!aud_cal || aud_cal->cal_size == 0) {
+ pr_err("%s: No calibration data to send!\n", __func__);
+ goto done;
+ }
+
+ adm_params.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(20), APR_PKT_VER);
+ adm_params.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(adm_params));
+ adm_params.hdr.src_svc = APR_SVC_ADM;
+ adm_params.hdr.src_domain = APR_DOMAIN_APPS;
+ adm_params.hdr.src_port = port_id;
+ adm_params.hdr.dest_svc = APR_SVC_ADM;
+ adm_params.hdr.dest_domain = APR_DOMAIN_ADSP;
+ adm_params.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ adm_params.hdr.token = port_id;
+ adm_params.hdr.opcode = ADM_CMD_SET_PARAMS;
+ adm_params.payload = aud_cal->cal_paddr;
+ adm_params.payload_size = aud_cal->cal_size;
+
+ atomic_set(&this_adm.copp_stat[index], 0);
+ pr_debug("%s: Sending SET_PARAMS payload = 0x%x, size = %d\n",
+ __func__, adm_params.payload, adm_params.payload_size);
+ result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_params);
+ if (result < 0) {
+ pr_err("%s: Set params failed port = %d payload = 0x%x\n",
+ __func__, port_id, aud_cal->cal_paddr);
+ goto done;
+ }
+ /* Wait for the callback */
+ result = wait_event_timeout(this_adm.wait,
+ atomic_read(&this_adm.copp_stat[index]),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!result)
+ pr_err("%s: Set params timed out port = %d, payload = 0x%x\n",
+ __func__, port_id, aud_cal->cal_paddr);
+done:
+ return;
+}
+
+void send_adm_cal(int port_id, int path)
+{
+ s32 acdb_path;
+ struct acdb_cal_block aud_cal;
+
+ pr_debug("%s\n", __func__);
+
+ /* Maps audio_dev_ctrl path definition to ACDB definition */
+ acdb_path = path - 1;
+ if ((acdb_path >= NUM_AUDPROC_BUFFERS) ||
+ (acdb_path < 0)) {
+ pr_err("%s: Path is not RX or TX, path = %d\n",
+ __func__, path);
+ goto done;
+ }
+
+ pr_debug("%s: Sending audproc cal\n", __func__);
+ get_audproc_cal(acdb_path, &aud_cal);
+ send_cal(port_id, &aud_cal);
+
+ pr_debug("%s: Sending audvol cal\n", __func__);
+ get_audvol_cal(acdb_path, &aud_cal);
+ send_cal(port_id, &aud_cal);
+done:
+ return;
+}
+
+/* This function issues routing command of ASM stream
+ * to ADM mixer associated with a particular AFE port
+ */
+int adm_cmd_map(int port_id, int session_id)
+{
+ struct adm_routings_command route;
+ int ret = 0;
+ int index = afe_get_port_index(port_id);
+
+ pr_debug("%s: port %x session %x\n", __func__, port_id, session_id);
+
+ if (!atomic_read(&this_adm.copp_cnt[index]))
+ return 0;
+
+ route.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ route.hdr.pkt_size = sizeof(route);
+ route.hdr.src_svc = 0;
+ route.hdr.src_domain = APR_DOMAIN_APPS;
+ route.hdr.src_port = port_id;
+ route.hdr.dest_svc = APR_SVC_ADM;
+ route.hdr.dest_domain = APR_DOMAIN_ADSP;
+ route.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ route.hdr.token = port_id;
+ route.hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS;
+ route.num_sessions = 1;
+ route.session[0].id = session_id;
+ route.session[0].num_copps = 1;
+ route.session[0].copp_id[0] =
+ atomic_read(&this_adm.copp_id[index]);
+
+ /* This rule can change */
+ if ((port_id & 0x1))
+ route.path = AUDIO_TX;
+ else
+ route.path = AUDIO_RX;
+
+ atomic_set(&this_adm.copp_stat[index], 0);
+
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&route);
+ if (ret < 0) {
+ pr_err("%s: ADM routing for port %d failed\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ ret = wait_event_timeout(this_adm.wait,
+ atomic_read(&this_adm.copp_stat[index]),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: ADM cmd Route failed for port %d\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ }
+
+fail_cmd:
+ return ret;
+}
+
+/* This function establish routing of ASM stream to a particular
+ * ADM mixer that is routed to a particular hardware port
+ * session id must be in range of 0 ~ 31.
+ */
+int adm_route_session(int port_id, uint session_id, int set)
+{
+ int rc = 0;
+ int index;
+
+ pr_debug("%s: port %x session %x set %x\n", __func__,
+ port_id, session_id, set);
+
+ index = afe_get_port_index(port_id);
+
+ if (index >= AFE_MAX_PORTS) {
+ pr_err("%s port idi[%d] out of limit[%d]\n", __func__,
+ port_id, AFE_MAX_PORTS);
+ return -ENODEV;
+ }
+
+ if (set) {
+ set_bit(session_id, &this_adm.sessions[index]);
+ rc = adm_cmd_map(port_id, session_id); /* not thread safe */
+ } else /* Not sure how to deroute yet */
+ clear_bit(session_id, &this_adm.sessions[index]);
+
+ return rc;
+}
+
+/* This function instantiates a mixer in QDSP6 audio path for
+ * given audio hardware port. Topology should be made part
+ * of audio calibration
+ */
+int adm_open_mixer(int port_id, int path, int rate,
+ int channel_mode, int topology) {
+ struct adm_copp_open_command open;
+ int ret = 0;
+ u32 i;
+ int index;
+
+ pr_debug("%s: port %d path:%d rate:%d mode:%d\n", __func__,
+ port_id, path, rate, channel_mode);
+
+ if (afe_validate_port(port_id) < 0) {
+ pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+ return -ENODEV;
+ }
+
+ index = afe_get_port_index(port_id);
+ if (this_adm.apr == NULL) {
+ this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+ 0xFFFFFFFF, &this_adm);
+ if (this_adm.apr == NULL) {
+ pr_err("%s: Unable to register ADM\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ }
+
+ if (atomic_read(&this_adm.copp_cnt[index]) == 0) {
+
+ open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ open.hdr.pkt_size = sizeof(open);
+ open.hdr.src_svc = APR_SVC_ADM;
+ open.hdr.src_domain = APR_DOMAIN_APPS;
+ open.hdr.src_port = port_id;
+ open.hdr.dest_svc = APR_SVC_ADM;
+ open.hdr.dest_domain = APR_DOMAIN_ADSP;
+ open.hdr.dest_port = port_id;
+ open.hdr.token = port_id;
+ open.hdr.opcode = ADM_CMD_COPP_OPEN;
+
+ open.mode = path;
+ open.endpoint_id1 = port_id;
+ open.endpoint_id2 = 0xFFFF;
+
+ open.topology_id = get_adm_topology();
+ if (open.topology_id == 0)
+ open.topology_id = topology;
+
+ open.channel_config = channel_mode & 0x00FF;
+ open.rate = rate;
+
+ pr_debug("%s: channel_config=%d port_id=%d rate=%d\
+ topology_id=0x%X\n", __func__, open.channel_config,\
+ open.endpoint_id1, open.rate,\
+ open.topology_id);
+
+ atomic_set(&this_adm.copp_stat[index], 0);
+
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+ if (ret < 0) {
+ pr_err("%s:ADM enable for port %d failed\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ /* Wait for the callback with copp id */
+ ret = wait_event_timeout(this_adm.wait,
+ atomic_read(&this_adm.copp_stat[index]),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s ADM open failed for port %d\n", __func__,
+ port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ }
+ atomic_inc(&this_adm.copp_cnt[index]);
+
+ /* Set up routing for cached session */
+ for (i = find_first_bit(&this_adm.sessions[index], ASM_MAX_SESSION);
+ i < ASM_MAX_SESSION; i = find_next_bit(&this_adm.sessions[index],
+ ASM_MAX_SESSION, i + 1))
+ adm_cmd_map(port_id, i); /* Not thread safe */
+
+fail_cmd:
+ return ret;
+}
+
+int adm_open(int port_id, int path, int rate, int channel_mode, int topology)
+{
+ struct adm_copp_open_command open;
+ int ret = 0;
+ int index;
+
+ pr_debug("%s: port %d path:%d rate:%d mode:%d\n", __func__,
+ port_id, path, rate, channel_mode);
+
+ if (afe_validate_port(port_id) < 0) {
+ pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+ return -ENODEV;
+ }
+
+ index = afe_get_port_index(port_id);
+ pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+
+ if (this_adm.apr == NULL) {
+ this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+ 0xFFFFFFFF, &this_adm);
+ if (this_adm.apr == NULL) {
+ pr_err("%s: Unable to register ADM\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+#ifdef CONFIG_MSM8X60_RTAC
+ rtac_set_adm_handle(this_adm.apr);
+#endif
+ }
+
+
+ /* Create a COPP if port id are not enabled */
+ if (atomic_read(&this_adm.copp_cnt[index]) == 0) {
+
+ open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ open.hdr.pkt_size = sizeof(open);
+ open.hdr.src_svc = APR_SVC_ADM;
+ open.hdr.src_domain = APR_DOMAIN_APPS;
+ open.hdr.src_port = port_id;
+ open.hdr.dest_svc = APR_SVC_ADM;
+ open.hdr.dest_domain = APR_DOMAIN_ADSP;
+ open.hdr.dest_port = port_id;
+ open.hdr.token = port_id;
+ open.hdr.opcode = ADM_CMD_COPP_OPEN;
+
+ open.mode = path;
+ open.endpoint_id1 = port_id;
+ open.endpoint_id2 = 0xFFFF;
+
+ open.topology_id = get_adm_topology();
+ if (open.topology_id == 0)
+ open.topology_id = topology;
+
+ open.channel_config = channel_mode & 0x00FF;
+ open.rate = rate;
+
+ pr_debug("%s: channel_config=%d port_id=%d rate=%d\
+ topology_id=0x%X\n", __func__, open.channel_config,\
+ open.endpoint_id1, open.rate,\
+ open.topology_id);
+
+ atomic_set(&this_adm.copp_stat[index], 0);
+
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+ if (ret < 0) {
+ pr_err("%s:ADM enable for port %d failed\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ /* Wait for the callback with copp id */
+ ret = wait_event_timeout(this_adm.wait,
+ atomic_read(&this_adm.copp_stat[index]),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s ADM open failed for port %d\n", __func__,
+ port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ }
+ atomic_inc(&this_adm.copp_cnt[index]);
+ return 0;
+
+fail_cmd:
+
+ return ret;
+}
+
+int adm_matrix_map(int session_id, int path, int num_copps,
+ unsigned int *port_id, int copp_id)
+{
+ struct adm_routings_command route;
+ int ret = 0, i = 0;
+ /* Assumes port_ids have already been validated during adm_open */
+ int index = afe_get_port_index(copp_id);
+
+ pr_debug("%s: session 0x%x path:%d num_copps:%d port_id[0]:%d\n",
+ __func__, session_id, path, num_copps, port_id[0]);
+
+ route.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ route.hdr.pkt_size = sizeof(route);
+ route.hdr.src_svc = 0;
+ route.hdr.src_domain = APR_DOMAIN_APPS;
+ route.hdr.src_port = copp_id;
+ route.hdr.dest_svc = APR_SVC_ADM;
+ route.hdr.dest_domain = APR_DOMAIN_ADSP;
+ route.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ route.hdr.token = copp_id;
+ route.hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS;
+ route.num_sessions = 1;
+ route.session[0].id = session_id;
+ route.session[0].num_copps = num_copps;
+
+ for (i = 0; i < num_copps; i++) {
+ int tmp;
+ tmp = afe_get_port_index(port_id[i]);
+
+ pr_debug("%s: port_id[%d]: %d, index: %d\n", __func__, i,
+ port_id[i], tmp);
+
+ route.session[0].copp_id[i] =
+ atomic_read(&this_adm.copp_id[tmp]);
+ }
+ if (num_copps % 2)
+ route.session[0].copp_id[i] = 0;
+
+ switch (path) {
+ case 0x1:
+ route.path = AUDIO_RX;
+ break;
+ case 0x2:
+ case 0x3:
+ route.path = AUDIO_TX;
+ break;
+ default:
+ pr_err("%s: Wrong path set[%d]\n", __func__, path);
+ break;
+ }
+ atomic_set(&this_adm.copp_stat[index], 0);
+
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&route);
+ if (ret < 0) {
+ pr_err("%s: ADM routing for port %d failed\n",
+ __func__, port_id[0]);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ ret = wait_event_timeout(this_adm.wait,
+ atomic_read(&this_adm.copp_stat[index]),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: ADM cmd Route failed for port %d\n",
+ __func__, port_id[0]);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ for (i = 0; i < num_copps; i++)
+ send_adm_cal(port_id[i], path);
+
+#ifdef CONFIG_MSM8X60_RTAC
+ for (i = 0; i < num_copps; i++)
+ rtac_add_adm_device(port_id[i], session_id);
+#endif
+ return 0;
+
+fail_cmd:
+
+ return ret;
+}
+
+int adm_memory_map_regions(uint32_t *buf_add, uint32_t mempool_id,
+ uint32_t *bufsz, uint32_t bufcnt)
+{
+ struct adm_cmd_memory_map_regions *mmap_regions = NULL;
+ struct adm_memory_map_regions *mregions = NULL;
+ void *mmap_region_cmd = NULL;
+ void *payload = NULL;
+ int ret = 0;
+ int i = 0;
+ int cmd_size = 0;
+
+ pr_info("%s\n", __func__);
+ if (this_adm.apr == NULL) {
+ this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+ 0xFFFFFFFF, &this_adm);
+ if (this_adm.apr == NULL) {
+ pr_err("%s: Unable to register ADM\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+#ifdef CONFIG_MSM8X60_RTAC
+ rtac_set_adm_handle(this_adm.apr);
+#endif
+ }
+
+ cmd_size = sizeof(struct adm_cmd_memory_map_regions)
+ + sizeof(struct adm_memory_map_regions) * bufcnt;
+
+ mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+ if (!mmap_region_cmd) {
+ pr_err("%s: allocate mmap_region_cmd failed\n", __func__);
+ return -ENOMEM;
+ }
+ mmap_regions = (struct adm_cmd_memory_map_regions *)mmap_region_cmd;
+ mmap_regions->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mmap_regions->hdr.pkt_size = cmd_size;
+ mmap_regions->hdr.src_port = 0;
+ mmap_regions->hdr.dest_port = 0;
+ mmap_regions->hdr.token = 0;
+ mmap_regions->hdr.opcode = ADM_CMD_MEMORY_MAP_REGIONS;
+ mmap_regions->mempool_id = mempool_id & 0x00ff;
+ mmap_regions->nregions = bufcnt & 0x00ff;
+ pr_debug("%s: map_regions->nregions = %d\n", __func__,
+ mmap_regions->nregions);
+ payload = ((u8 *) mmap_region_cmd +
+ sizeof(struct adm_cmd_memory_map_regions));
+ mregions = (struct adm_memory_map_regions *)payload;
+
+ for (i = 0; i < bufcnt; i++) {
+ mregions->phys = buf_add[i];
+ mregions->buf_size = bufsz[i];
+ ++mregions;
+ }
+
+ atomic_set(&this_adm.copp_stat[0], 0);
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *) mmap_region_cmd);
+ if (ret < 0) {
+ pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
+ mmap_regions->hdr.opcode, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_adm.wait,
+ atomic_read(&this_adm.copp_stat[0]), 5 * HZ);
+ if (!ret) {
+ pr_err("%s: timeout. waited for memory_map\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+fail_cmd:
+ kfree(mmap_region_cmd);
+ return ret;
+}
+
+int adm_memory_unmap_regions(uint32_t *buf_add, uint32_t *bufsz,
+ uint32_t bufcnt)
+{
+ struct adm_cmd_memory_unmap_regions *unmap_regions = NULL;
+ struct adm_memory_unmap_regions *mregions = NULL;
+ void *unmap_region_cmd = NULL;
+ void *payload = NULL;
+ int ret = 0;
+ int i = 0;
+ int cmd_size = 0;
+
+ pr_info("%s\n", __func__);
+
+ if (this_adm.apr == NULL) {
+ pr_err("%s APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ cmd_size = sizeof(struct adm_cmd_memory_unmap_regions)
+ + sizeof(struct adm_memory_unmap_regions) * bufcnt;
+
+ unmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+ if (!unmap_region_cmd) {
+ pr_err("%s: allocate unmap_region_cmd failed\n", __func__);
+ return -ENOMEM;
+ }
+ unmap_regions = (struct adm_cmd_memory_unmap_regions *)
+ unmap_region_cmd;
+ unmap_regions->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ unmap_regions->hdr.pkt_size = cmd_size;
+ unmap_regions->hdr.src_port = 0;
+ unmap_regions->hdr.dest_port = 0;
+ unmap_regions->hdr.token = 0;
+ unmap_regions->hdr.opcode = ADM_CMD_MEMORY_UNMAP_REGIONS;
+ unmap_regions->nregions = bufcnt & 0x00ff;
+ unmap_regions->reserved = 0;
+ pr_debug("%s: unmap_regions->nregions = %d\n", __func__,
+ unmap_regions->nregions);
+ payload = ((u8 *) unmap_region_cmd +
+ sizeof(struct adm_cmd_memory_unmap_regions));
+ mregions = (struct adm_memory_unmap_regions *)payload;
+
+ for (i = 0; i < bufcnt; i++) {
+ mregions->phys = buf_add[i];
+ ++mregions;
+ }
+ atomic_set(&this_adm.copp_stat[0], 0);
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *) unmap_region_cmd);
+ if (ret < 0) {
+ pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
+ unmap_regions->hdr.opcode, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_adm.wait,
+ atomic_read(&this_adm.copp_stat[0]), 5 * HZ);
+ if (!ret) {
+ pr_err("%s: timeout. waited for memory_unmap\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+fail_cmd:
+ kfree(unmap_region_cmd);
+ return ret;
+}
+
+#ifdef CONFIG_MSM8X60_RTAC
+int adm_get_copp_id(int port_id)
+{
+ pr_debug("%s\n", __func__);
+
+ if (port_id < 0) {
+ pr_err("%s: invalid port_id = %d\n", __func__, port_id);
+ return -EINVAL;
+ }
+
+ return atomic_read(&this_adm.copp_id[port_id]);
+}
+#endif
+
+int adm_close(int port_id)
+{
+ struct apr_hdr close;
+
+ int ret = 0;
+ int index = afe_get_port_index(port_id);
+
+ pr_info("%s port_id=%d index %d\n", __func__, port_id, index);
+
+ if (!(atomic_read(&this_adm.copp_cnt[index]))) {
+ pr_err("%s: copp count for port[%d]is 0\n", __func__, port_id);
+
+ goto fail_cmd;
+ }
+ atomic_dec(&this_adm.copp_cnt[index]);
+ if (!(atomic_read(&this_adm.copp_cnt[index]))) {
+
+ close.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ close.pkt_size = sizeof(close);
+ close.src_svc = APR_SVC_ADM;
+ close.src_domain = APR_DOMAIN_APPS;
+ close.src_port = port_id;
+ close.dest_svc = APR_SVC_ADM;
+ close.dest_domain = APR_DOMAIN_ADSP;
+ close.dest_port = atomic_read(&this_adm.copp_id[index]);
+ close.token = port_id;
+ close.opcode = ADM_CMD_COPP_CLOSE;
+
+ atomic_set(&this_adm.copp_id[index], RESET_COPP_ID);
+ atomic_set(&this_adm.copp_stat[index], 0);
+
+
+ pr_debug("%s:coppid %d portid=%d index=%d coppcnt=%d\n",
+ __func__,
+ atomic_read(&this_adm.copp_id[index]),
+ port_id, index,
+ atomic_read(&this_adm.copp_cnt[index]));
+
+ ret = apr_send_pkt(this_adm.apr, (uint32_t *)&close);
+ if (ret < 0) {
+ pr_err("%s ADM close failed\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_adm.wait,
+ atomic_read(&this_adm.copp_stat[index]),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: ADM cmd Route failed for port %d\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+#ifdef CONFIG_MSM8X60_RTAC
+ rtac_remove_adm_device(port_id);
+#endif
+ }
+
+fail_cmd:
+ return ret;
+}
+
+static int __init adm_init(void)
+{
+ int i = 0;
+ init_waitqueue_head(&this_adm.wait);
+ this_adm.apr = NULL;
+
+ for (i = 0; i < AFE_MAX_PORTS; i++) {
+ atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
+ atomic_set(&this_adm.copp_cnt[i], 0);
+ atomic_set(&this_adm.copp_stat[i], 0);
+ }
+ return 0;
+}
+
+device_initcall(adm_init);
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
new file mode 100644
index 0000000..500ceb5
--- /dev/null
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -0,0 +1,868 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <sound/apr_audio.h>
+#include <sound/q6afe.h>
+
+struct afe_ctl {
+ void *apr;
+ atomic_t state;
+ atomic_t status;
+ wait_queue_head_t wait;
+ struct task_struct *task;
+};
+
+static struct afe_ctl this_afe;
+
+#define TIMEOUT_MS 1000
+#define Q6AFE_MAX_VOLUME 0x3FFF
+
+#define SIZEOF_CFG_CMD(y) \
+ (sizeof(struct apr_hdr) + sizeof(u16) + (sizeof(struct y)))
+
+static int32_t afe_callback(struct apr_client_data *data, void *priv)
+{
+ if (data->opcode == RESET_EVENTS) {
+ pr_debug("q6afe: reset event = %d %d apr[%p]\n",
+ data->reset_event, data->reset_proc, this_afe.apr);
+ if (this_afe.apr) {
+ apr_reset(this_afe.apr);
+ atomic_set(&this_afe.state, 0);
+ this_afe.apr = NULL;
+ }
+ /* send info to user */
+ pr_debug("task_name = %s pid = %d\n",
+ this_afe.task->comm, this_afe.task->pid);
+ send_sig(SIGUSR1, this_afe.task, 0);
+ }
+ if (data->payload_size) {
+ uint32_t *payload;
+ payload = data->payload;
+ pr_debug("%s: cmd = 0x%x status = 0x%x\n", __func__,
+ payload[0], payload[1]);
+ /* payload[1] contains the error status for response */
+ if (payload[1] != 0) {
+ atomic_set(&this_afe.status, -1);
+ pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
+ __func__, payload[0], payload[1]);
+ }
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ switch (payload[0]) {
+ case AFE_PORT_AUDIO_IF_CONFIG:
+ case AFE_PORT_CMD_STOP:
+ case AFE_PORT_CMD_START:
+ case AFE_PORT_CMD_LOOPBACK:
+ case AFE_PORT_CMD_SIDETONE_CTL:
+ case AFE_PORT_CMD_SET_PARAM:
+ case AFE_PSEUDOPORT_CMD_START:
+ case AFE_PSEUDOPORT_CMD_STOP:
+ atomic_set(&this_afe.state, 0);
+ wake_up(&this_afe.wait);
+ break;
+ default:
+ pr_err("Unknown cmd 0x%x\n",
+ payload[0]);
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+int afe_validate_port(u16 port_id)
+{
+ int ret;
+
+ switch (port_id) {
+ case PRIMARY_I2S_RX:
+ case PRIMARY_I2S_TX:
+ case PCM_RX:
+ case PCM_TX:
+ case SECONDARY_I2S_RX:
+ case SECONDARY_I2S_TX:
+ case MI2S_RX:
+ case MI2S_TX:
+ case HDMI_RX:
+ case RSVD_2:
+ case RSVD_3:
+ case DIGI_MIC_TX:
+ case VOICE_RECORD_RX:
+ case VOICE_RECORD_TX:
+ case VOICE_PLAYBACK_TX:
+ case SLIMBUS_0_RX:
+ case SLIMBUS_0_TX:
+ case INT_BT_SCO_RX:
+ case INT_BT_SCO_TX:
+ case INT_BT_A2DP_RX:
+ case INT_FM_RX:
+ case INT_FM_TX:
+ {
+ ret = 0;
+ break;
+ }
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+int afe_get_port_index(u16 port_id)
+{
+ switch (port_id) {
+ case PRIMARY_I2S_RX: return IDX_PRIMARY_I2S_RX;
+ case PRIMARY_I2S_TX: return IDX_PRIMARY_I2S_TX;
+ case PCM_RX: return IDX_PCM_RX;
+ case PCM_TX: return IDX_PCM_TX;
+ case SECONDARY_I2S_RX: return IDX_SECONDARY_I2S_RX;
+ case SECONDARY_I2S_TX: return IDX_SECONDARY_I2S_TX;
+ case MI2S_RX: return IDX_MI2S_RX;
+ case MI2S_TX: return IDX_MI2S_TX;
+ case HDMI_RX: return IDX_HDMI_RX;
+ case RSVD_2: return IDX_RSVD_2;
+ case RSVD_3: return IDX_RSVD_3;
+ case DIGI_MIC_TX: return IDX_DIGI_MIC_TX;
+ case VOICE_RECORD_RX: return IDX_VOICE_RECORD_RX;
+ case VOICE_RECORD_TX: return IDX_VOICE_RECORD_TX;
+ case VOICE_PLAYBACK_TX: return IDX_VOICE_PLAYBACK_TX;
+ case SLIMBUS_0_RX: return IDX_SLIMBUS_0_RX;
+ case SLIMBUS_0_TX: return IDX_SLIMBUS_0_TX;
+ case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
+ case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
+ case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
+ case INT_FM_RX: return IDX_INT_FM_RX;
+ case INT_FM_TX: return IDX_INT_FM_TX;
+
+ default: return -EINVAL;
+ }
+}
+
+int afe_sizeof_cfg_cmd(u16 port_id)
+{
+ int ret_size;
+ switch (port_id) {
+ case PRIMARY_I2S_RX:
+ case PRIMARY_I2S_TX:
+ case SECONDARY_I2S_RX:
+ case SECONDARY_I2S_TX:
+ case MI2S_RX:
+ case MI2S_TX:
+ ret_size = SIZEOF_CFG_CMD(afe_port_mi2s_cfg);
+ break;
+ case HDMI_RX:
+ ret_size = SIZEOF_CFG_CMD(afe_port_hdmi_cfg);
+ break;
+ case SLIMBUS_0_RX:
+ case SLIMBUS_0_TX:
+ ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_cfg);
+ break;
+ case PCM_RX:
+ case PCM_TX:
+ default:
+ ret_size = SIZEOF_CFG_CMD(afe_port_pcm_cfg);
+ break;
+ }
+ return ret_size;
+}
+
+int afe_port_start_nowait(u16 port_id, union afe_port_config *afe_config,
+ u32 rate) /* This function is no blocking */
+{
+ struct afe_port_start_command start;
+ struct afe_audioif_config_command config;
+ int ret;
+
+ if (!afe_config) {
+ pr_err("%s: Error, no configuration data\n", __func__);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ pr_info("%s: %d %d\n", __func__, port_id, rate);
+
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ pr_info("%s: Register AFE\n", __func__);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ }
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = afe_sizeof_cfg_cmd(port_id);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = 0;
+ config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
+
+ if (afe_validate_port(port_id) < 0) {
+
+ pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
+ port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ config.port_id = port_id;
+ config.port = *afe_config;
+
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
+ if (ret < 0) {
+ pr_err("%s: AFE enable for port %d failed\n", __func__,
+ port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ start.hdr.pkt_size = sizeof(start);
+ start.hdr.src_port = 0;
+ start.hdr.dest_port = 0;
+ start.hdr.token = 0;
+ start.hdr.opcode = AFE_PORT_CMD_START;
+ start.port_id = port_id;
+ start.gain = 0x2000;
+ start.sample_rate = rate;
+
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
+
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("%s: AFE enable for port %d failed\n", __func__,
+ port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ if (this_afe.task != current)
+ this_afe.task = current;
+
+ pr_debug("task_name = %s pid = %d\n",
+ this_afe.task->comm, this_afe.task->pid);
+ return 0;
+
+fail_cmd:
+ return ret;
+}
+
+int afe_open(u16 port_id, union afe_port_config *afe_config, int rate)
+{
+ struct afe_port_start_command start;
+ struct afe_audioif_config_command config;
+ int ret = 0;
+
+ if (!afe_config) {
+ pr_err("%s: Error, no configuration data\n", __func__);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ pr_info("%s: %d %d\n", __func__, port_id, rate);
+
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ pr_info("%s: Register AFE\n", __func__);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ }
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = afe_sizeof_cfg_cmd(port_id);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = 0;
+ config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
+
+ if (afe_validate_port(port_id) < 0) {
+
+ pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
+ port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ config.port_id = port_id;
+ config.port = *afe_config;
+
+ atomic_set(&this_afe.state, 1);
+ atomic_set(&this_afe.status, 0);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
+ if (ret < 0) {
+ pr_err("%s: AFE enable for port %d failed\n", __func__,
+ port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait,
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ start.hdr.pkt_size = sizeof(start);
+ start.hdr.src_port = 0;
+ start.hdr.dest_port = 0;
+ start.hdr.token = 0;
+ start.hdr.opcode = AFE_PORT_CMD_START;
+ start.port_id = port_id;
+ start.gain = 0x2000;
+ start.sample_rate = rate;
+
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
+ if (ret < 0) {
+ pr_err("%s: AFE enable for port %d failed\n", __func__,
+ port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ ret = wait_event_timeout(this_afe.wait,
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ if (this_afe.task != current)
+ this_afe.task = current;
+
+ pr_debug("task_name = %s pid = %d\n",
+ this_afe.task->comm, this_afe.task->pid);
+ return 0;
+fail_cmd:
+ return ret;
+}
+
+int afe_loopback(u16 enable, u16 rx_port, u16 tx_port)
+{
+ struct afe_loopback_command lb_cmd;
+ int ret = 0;
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ pr_info("%s: Register AFE\n", __func__);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ }
+ lb_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(20), APR_PKT_VER);
+ lb_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(lb_cmd) - APR_HDR_SIZE);
+ lb_cmd.hdr.src_port = 0;
+ lb_cmd.hdr.dest_port = 0;
+ lb_cmd.hdr.token = 0;
+ lb_cmd.hdr.opcode = AFE_PORT_CMD_LOOPBACK;
+ lb_cmd.tx_port_id = tx_port;
+ lb_cmd.rx_port_id = rx_port;
+ lb_cmd.mode = 0xFFFF;
+ lb_cmd.enable = (enable ? 1 : 0);
+ atomic_set(&this_afe.state, 1);
+
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
+ if (ret < 0) {
+ pr_err("%s: AFE loopback failed\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ ret = wait_event_timeout(this_afe.wait,
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ }
+done:
+ return ret;
+}
+
+
+int afe_loopback_gain(u16 port_id, u16 volume)
+{
+ struct afe_port_cmd_set_param set_param;
+ int ret = 0;
+
+ if (this_afe.apr == NULL) {
+ pr_err("%s: AFE is not opened\n", __func__);
+ ret = -EPERM;
+ goto fail_cmd;
+ }
+
+ if (afe_validate_port(port_id) < 0) {
+
+ pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
+ port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ /* RX ports numbers are even .TX ports numbers are odd. */
+ if (port_id % 2 == 0) {
+ pr_err("%s: Failed : afe loopback gain only for TX ports."
+ " port_id %d\n", __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ pr_debug("%s: %d %hX\n", __func__, port_id, volume);
+
+ set_param.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ set_param.hdr.pkt_size = sizeof(set_param);
+ set_param.hdr.src_port = 0;
+ set_param.hdr.dest_port = 0;
+ set_param.hdr.token = 0;
+ set_param.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
+
+ set_param.port_id = port_id;
+ set_param.payload_size = sizeof(struct afe_param_payload);
+ set_param.payload_address = 0;
+
+ set_param.payload.module_id = AFE_MODULE_ID_PORT_INFO;
+ set_param.payload.param_id = AFE_PARAM_ID_LOOPBACK_GAIN;
+ set_param.payload.param_size = sizeof(struct afe_param_loopback_gain);
+ set_param.payload.reserved = 0;
+
+ set_param.payload.param.loopback_gain.gain = volume;
+ set_param.payload.param.loopback_gain.reserved = 0;
+
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
+ if (ret < 0) {
+ pr_err("%s: AFE param set failed for port %d\n",
+ __func__, port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait,
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (ret < 0) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return ret;
+}
+
+int afe_start_pseudo_port(u16 port_id)
+{
+ int ret = 0;
+ struct afe_pseudoport_start_command start;
+
+ pr_info("%s: port_id=%d\n", __func__, port_id);
+
+ if (this_afe.apr == NULL) {
+ this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+ 0xFFFFFFFF, &this_afe);
+ pr_info("%s: Register AFE\n", __func__);
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Unable to register AFE\n", __func__);
+ ret = -ENODEV;
+ return ret;
+ }
+ }
+
+ start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ start.hdr.pkt_size = sizeof(start);
+ start.hdr.src_port = 0;
+ start.hdr.dest_port = 0;
+ start.hdr.token = 0;
+ start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
+ start.port_id = port_id;
+ start.timing = 1;
+
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
+ if (ret < 0) {
+ pr_err("%s: AFE enable for port %d failed %d\n",
+ __func__, port_id, ret);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ ret = wait_event_timeout(this_afe.wait,
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ return 0;
+}
+
+int afe_stop_pseudo_port(u16 port_id)
+{
+ int ret = 0;
+ struct afe_pseudoport_stop_command stop;
+
+ pr_info("%s: port_id=%d\n", __func__, port_id);
+
+ if (this_afe.apr == NULL) {
+ pr_err("%s: AFE is already closed\n", __func__);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ stop.hdr.pkt_size = sizeof(stop);
+ stop.hdr.src_port = 0;
+ stop.hdr.dest_port = 0;
+ stop.hdr.token = 0;
+ stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
+ stop.port_id = port_id;
+ stop.reserved = 0;
+
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+ if (ret < 0) {
+ pr_err("%s: AFE close failed %d\n", __func__, ret);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ ret = wait_event_timeout(this_afe.wait,
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_afelb;
+static struct dentry *debugfs_afelb_gain;
+
+static int afe_debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ pr_info("debug intf %s\n", (char *) file->private_data);
+ return 0;
+}
+
+static int afe_get_parameters(char *buf, long int *param1, int num_of_par)
+{
+ char *token;
+ int base, cnt;
+
+ token = strsep(&buf, " ");
+
+ for (cnt = 0; cnt < num_of_par; cnt++) {
+ if (token != NULL) {
+ if ((token[1] == 'x') || (token[1] == 'X'))
+ base = 16;
+ else
+ base = 10;
+
+ if (strict_strtoul(token, base, ¶m1[cnt]) != 0)
+ return -EINVAL;
+
+ token = strsep(&buf, " ");
+ } else
+ return -EINVAL;
+ }
+ return 0;
+}
+#define AFE_LOOPBACK_ON (1)
+#define AFE_LOOPBACK_OFF (0)
+static ssize_t afe_debug_write(struct file *filp,
+ const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ char *lb_str = filp->private_data;
+ char lbuf[32];
+ int rc;
+ unsigned long param[5];
+
+ if (cnt > sizeof(lbuf) - 1)
+ return -EINVAL;
+
+ rc = copy_from_user(lbuf, ubuf, cnt);
+ if (rc)
+ return -EFAULT;
+
+ lbuf[cnt] = '\0';
+
+ if (!strcmp(lb_str, "afe_loopback")) {
+ rc = afe_get_parameters(lbuf, param, 3);
+ if (!rc) {
+ pr_info("%s %lu %lu %lu\n", lb_str, param[0], param[1],
+ param[2]);
+
+ if ((param[0] != AFE_LOOPBACK_ON) && (param[0] !=
+ AFE_LOOPBACK_OFF)) {
+ pr_err("%s: Error, parameter 0 incorrect\n",
+ __func__);
+ rc = -EINVAL;
+ goto afe_error;
+ }
+ if ((afe_validate_port(param[1]) < 0) ||
+ (afe_validate_port(param[2])) < 0) {
+ pr_err("%s: Error, invalid afe port\n",
+ __func__);
+ }
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Error, AFE not opened\n", __func__);
+ rc = -EINVAL;
+ } else {
+ rc = afe_loopback(param[0], param[1], param[2]);
+ }
+ } else {
+ pr_err("%s: Error, invalid parameters\n", __func__);
+ rc = -EINVAL;
+ }
+
+ } else if (!strcmp(lb_str, "afe_loopback_gain")) {
+ rc = afe_get_parameters(lbuf, param, 2);
+ if (!rc) {
+ pr_info("%s %lu %lu\n", lb_str, param[0], param[1]);
+
+ if (afe_validate_port(param[0]) < 0) {
+ pr_err("%s: Error, invalid afe port\n",
+ __func__);
+ rc = -EINVAL;
+ goto afe_error;
+ }
+
+ if (param[1] < 0 || param[1] > 100) {
+ pr_err("%s: Error, volume shoud be 0 to 100"
+ " percentage param = %lu\n",
+ __func__, param[1]);
+ rc = -EINVAL;
+ goto afe_error;
+ }
+
+ param[1] = (Q6AFE_MAX_VOLUME * param[1]) / 100;
+
+ if (this_afe.apr == NULL) {
+ pr_err("%s: Error, AFE not opened\n", __func__);
+ rc = -EINVAL;
+ } else {
+ rc = afe_loopback_gain(param[0], param[1]);
+ }
+ } else {
+ pr_err("%s: Error, invalid parameters\n", __func__);
+ rc = -EINVAL;
+ }
+ }
+
+afe_error:
+ if (rc == 0)
+ rc = cnt;
+ else
+ pr_err("%s: rc = %d\n", __func__, rc);
+
+ return rc;
+}
+
+static const struct file_operations afe_debug_fops = {
+ .open = afe_debug_open,
+ .write = afe_debug_write
+};
+#endif
+int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain)
+{
+ struct afe_port_sidetone_command cmd_sidetone;
+ int ret = 0;
+
+ pr_info("%s: tx_port_id:%d rx_port_id:%d enable:%d gain:%d\n", __func__,
+ tx_port_id, rx_port_id, enable, gain);
+ cmd_sidetone.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ cmd_sidetone.hdr.pkt_size = sizeof(cmd_sidetone);
+ cmd_sidetone.hdr.src_port = 0;
+ cmd_sidetone.hdr.dest_port = 0;
+ cmd_sidetone.hdr.token = 0;
+ cmd_sidetone.hdr.opcode = AFE_PORT_CMD_SIDETONE_CTL;
+ cmd_sidetone.tx_port_id = tx_port_id;
+ cmd_sidetone.rx_port_id = rx_port_id;
+ cmd_sidetone.gain = gain;
+ cmd_sidetone.enable = enable;
+
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_sidetone);
+ if (ret < 0) {
+ pr_err("%s: AFE sidetone failed for tx_port:%d rx_port:%d\n",
+ __func__, tx_port_id, rx_port_id);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait,
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (ret < 0) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return ret;
+}
+
+int afe_port_stop_nowait(int port_id)
+{
+ struct afe_port_stop_command stop;
+ int ret = 0;
+
+ if (this_afe.apr == NULL) {
+ pr_err("AFE is already closed\n");
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ pr_info("%s: port_id=%d\n", __func__, port_id);
+ stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ stop.hdr.pkt_size = sizeof(stop);
+ stop.hdr.src_port = 0;
+ stop.hdr.dest_port = 0;
+ stop.hdr.token = 0;
+ stop.hdr.opcode = AFE_PORT_CMD_STOP;
+ stop.port_id = port_id;
+ stop.reserved = 0;
+
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+
+ if (ret == -ENETRESET) {
+ pr_info("%s: Need to reset, calling APR deregister", __func__);
+ return apr_deregister(this_afe.apr);
+ } else if (IS_ERR_VALUE(ret)) {
+ pr_err("%s: AFE close failed\n", __func__);
+ ret = -EINVAL;
+ }
+
+fail_cmd:
+ return ret;
+
+}
+
+int afe_close(int port_id)
+{
+ struct afe_port_stop_command stop;
+ int ret = 0;
+
+ if (this_afe.apr == NULL) {
+ pr_err("AFE is already closed\n");
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ pr_info("%s: port_id=%d\n", __func__, port_id);
+ stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ stop.hdr.pkt_size = sizeof(stop);
+ stop.hdr.src_port = 0;
+ stop.hdr.dest_port = 0;
+ stop.hdr.token = 0;
+ stop.hdr.opcode = AFE_PORT_CMD_STOP;
+ stop.port_id = port_id;
+ stop.reserved = 0;
+
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+
+ if (ret == -ENETRESET) {
+ pr_info("%s: Need to reset, calling APR deregister", __func__);
+ return apr_deregister(this_afe.apr);
+ }
+
+ if (ret < 0) {
+ pr_err("%s: AFE close failed\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait,
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+fail_cmd:
+ return ret;
+}
+
+static int __init afe_init(void)
+{
+ init_waitqueue_head(&this_afe.wait);
+ atomic_set(&this_afe.state, 0);
+ atomic_set(&this_afe.status, 0);
+ this_afe.apr = NULL;
+#ifdef CONFIG_DEBUG_FS
+ debugfs_afelb = debugfs_create_file("afe_loopback",
+ S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback",
+ &afe_debug_fops);
+
+ debugfs_afelb_gain = debugfs_create_file("afe_loopback_gain",
+ S_IFREG | S_IWUGO, NULL, (void *) "afe_loopback_gain",
+ &afe_debug_fops);
+
+
+#endif
+ return 0;
+}
+
+static void __exit afe_exit(void)
+{
+#ifdef CONFIG_DEBUG_FS
+ if (debugfs_afelb)
+ debugfs_remove(debugfs_afelb);
+ if (debugfs_afelb_gain)
+ debugfs_remove(debugfs_afelb_gain);
+#endif
+}
+
+device_initcall(afe_init);
+__exitcall(afe_exit);
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
new file mode 100644
index 0000000..f5f1c63
--- /dev/null
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -0,0 +1,2600 @@
+
+/*
+ * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/dma-mapping.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+#include <mach/memory.h>
+#include <mach/debug_mm.h>
+#include <mach/peripheral-loader.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+#include <mach/qdsp6v2/rtac.h>
+#include <mach/msm_subsystem_map.h>
+#include <sound/apr_audio.h>
+#include <sound/q6asm.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#define TRUE 0x01
+#define FALSE 0x00
+#define READDONE_IDX_STATUS 0
+#define READDONE_IDX_BUFFER 1
+#define READDONE_IDX_SIZE 2
+#define READDONE_IDX_OFFSET 3
+#define READDONE_IDX_MSW_TS 4
+#define READDONE_IDX_LSW_TS 5
+#define READDONE_IDX_FLAGS 6
+#define READDONE_IDX_NUMFRAMES 7
+#define READDONE_IDX_ID 8
+
+static DEFINE_MUTEX(session_lock);
+
+/* session id: 0 reserved */
+static struct audio_client *session[SESSION_MAX+1];
+static int32_t q6asm_mmapcallback(struct apr_client_data *data, void *priv);
+static int32_t q6asm_callback(struct apr_client_data *data, void *priv);
+static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg);
+static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg);
+static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
+ uint32_t bufsz, uint32_t bufcnt);
+static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir,
+ uint32_t bufsz, uint32_t bufcnt);
+
+static void q6asm_reset_buf_state(struct audio_client *ac);
+
+struct asm_mmap {
+ atomic_t ref_cnt;
+ atomic_t cmd_state;
+ wait_queue_head_t cmd_wait;
+ void *apr;
+};
+
+static struct asm_mmap this_mmap;
+
+static int q6asm_session_alloc(struct audio_client *ac)
+{
+ int n;
+ mutex_lock(&session_lock);
+ for (n = 1; n <= SESSION_MAX; n++) {
+ if (!session[n]) {
+ session[n] = ac;
+ mutex_unlock(&session_lock);
+ return n;
+ }
+ }
+ mutex_unlock(&session_lock);
+ return -ENOMEM;
+}
+
+static void q6asm_session_free(struct audio_client *ac)
+{
+ pr_debug("%s: sessionid[%d]\n", __func__, ac->session);
+ mutex_lock(&session_lock);
+ session[ac->session] = 0;
+ mutex_unlock(&session_lock);
+ ac->session = 0;
+ return;
+}
+
+int q6asm_audio_client_buf_free(unsigned int dir,
+ struct audio_client *ac)
+{
+ struct audio_port_data *port;
+ int cnt = 0;
+ int rc = 0;
+ pr_debug("%s: Session id %d\n", __func__, ac->session);
+ mutex_lock(&ac->cmd_lock);
+ if (ac->io_mode == SYNC_IO_MODE) {
+ port = &ac->port[dir];
+ if (!port->buf) {
+ mutex_unlock(&ac->cmd_lock);
+ return 0;
+ }
+ cnt = port->max_buf_cnt - 1;
+
+ if (cnt >= 0) {
+ rc = q6asm_memory_unmap_regions(ac, dir,
+ port->buf[0].size,
+ port->max_buf_cnt);
+ if (rc < 0)
+ pr_err("%s CMD Memory_unmap_regions failed\n",
+ __func__);
+ }
+
+ while (cnt >= 0) {
+ if (port->buf[cnt].data) {
+ pr_debug("%s:data[%p]phys[%p][%p] cnt[%d]"
+ "mem_buffer[%p]\n",
+ __func__, (void *)port->buf[cnt].data,
+ (void *)port->buf[cnt].phys,
+ (void *)&port->buf[cnt].phys, cnt,
+ (void *)port->buf[cnt].mem_buffer);
+ if (IS_ERR((void *)port->buf[cnt].mem_buffer))
+ pr_err("%s:mem buffer invalid, error ="
+ "%ld\n", __func__,
+ PTR_ERR((void *)port->buf[cnt].mem_buffer));
+ else {
+ if (msm_subsystem_unmap_buffer(
+ port->buf[cnt].mem_buffer) < 0)
+ pr_err("%s: unmap buffer"
+ " failed\n", __func__);
+ }
+ free_contiguous_memory_by_paddr(
+ port->buf[cnt].phys);
+
+ port->buf[cnt].data = NULL;
+ port->buf[cnt].phys = 0;
+ --(port->max_buf_cnt);
+ }
+ --cnt;
+ }
+ kfree(port->buf);
+ port->buf = NULL;
+ }
+ mutex_unlock(&ac->cmd_lock);
+ return 0;
+}
+
+int q6asm_audio_client_buf_free_contiguous(unsigned int dir,
+ struct audio_client *ac)
+{
+ struct audio_port_data *port;
+ int cnt = 0;
+ int rc = 0;
+ pr_debug("%s: Session id %d\n", __func__, ac->session);
+ mutex_lock(&ac->cmd_lock);
+ port = &ac->port[dir];
+ if (!port->buf) {
+ mutex_unlock(&ac->cmd_lock);
+ return 0;
+ }
+ cnt = port->max_buf_cnt - 1;
+
+ if (cnt >= 0) {
+ rc = q6asm_memory_unmap(ac, port->buf[0].size, dir);
+ if (rc < 0)
+ pr_err("%s CMD Memory_unmap_regions failed\n",
+ __func__);
+ }
+
+ if (port->buf[0].data) {
+ pr_debug("%s:data[%p]phys[%p][%p] cnt[%d]\n",
+ __func__,
+ (void *)port->buf[0].data,
+ (void *)port->buf[0].phys,
+ (void *)&port->buf[0].phys, cnt);
+ dma_free_coherent(NULL,
+ port->buf[0].size * port->max_buf_cnt,
+ port->buf[0].data,
+ port->buf[0].phys);
+ }
+ while (cnt >= 0) {
+ port->buf[cnt].data = NULL;
+ port->buf[cnt].phys = 0;
+ cnt--;
+ }
+ port->max_buf_cnt = 0;
+ kfree(port->buf);
+ port->buf = NULL;
+ mutex_unlock(&ac->cmd_lock);
+ return 0;
+}
+
+void q6asm_audio_client_free(struct audio_client *ac)
+{
+ int loopcnt;
+ struct audio_port_data *port;
+ if (!ac || !ac->session)
+ return;
+ pr_debug("%s: Session id %d\n", __func__, ac->session);
+ if (ac->io_mode == SYNC_IO_MODE) {
+ for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
+ port = &ac->port[loopcnt];
+ if (!port->buf)
+ continue;
+ pr_debug("%s:loopcnt = %d\n", __func__, loopcnt);
+ q6asm_audio_client_buf_free(loopcnt, ac);
+ }
+ }
+
+ apr_deregister(ac->apr);
+ q6asm_session_free(ac);
+
+ pr_debug("%s: APR De-Register\n", __func__);
+ if (atomic_read(&this_mmap.ref_cnt) <= 0) {
+ pr_err("%s: APR Common Port Already Closed\n", __func__);
+ goto done;
+ }
+
+ atomic_dec(&this_mmap.ref_cnt);
+ if (atomic_read(&this_mmap.ref_cnt) == 0) {
+ apr_deregister(this_mmap.apr);
+ pr_debug("%s:APR De-Register common port\n", __func__);
+ }
+done:
+ kfree(ac);
+ return;
+}
+
+int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode)
+{
+ if (ac == NULL) {
+ pr_err("%s APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ if ((mode == ASYNC_IO_MODE) || (mode == SYNC_IO_MODE)) {
+ ac->io_mode = mode;
+ pr_debug("%s:Set Mode to %d\n", __func__, ac->io_mode);
+ return 0;
+ } else {
+ pr_err("%s:Not an valid IO Mode:%d\n", __func__, ac->io_mode);
+ return -EINVAL;
+ }
+}
+
+struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv)
+{
+ struct audio_client *ac;
+ int n;
+ int lcnt = 0;
+
+ ac = kzalloc(sizeof(struct audio_client), GFP_KERNEL);
+ if (!ac)
+ return NULL;
+ n = q6asm_session_alloc(ac);
+ if (n <= 0)
+ goto fail_session;
+ ac->session = n;
+ ac->cb = cb;
+ ac->priv = priv;
+ ac->io_mode = SYNC_IO_MODE;
+ ac->apr = apr_register("ADSP", "ASM", \
+ (apr_fn)q6asm_callback,\
+ ((ac->session) << 8 | 0x0001),\
+ ac);
+
+ if (ac->apr == NULL) {
+ pr_err("%s Registration with APR failed\n", __func__);
+ goto fail;
+ }
+#ifdef CONFIG_MSM8X60_RTAC
+ rtac_set_asm_handle(n, ac->apr);
+#endif
+ pr_debug("%s Registering the common port with APR\n", __func__);
+ if (atomic_read(&this_mmap.ref_cnt) == 0) {
+ this_mmap.apr = apr_register("ADSP", "ASM", \
+ (apr_fn)q6asm_mmapcallback,\
+ 0x0FFFFFFFF, &this_mmap);
+ if (this_mmap.apr == NULL) {
+ pr_debug("%s Unable to register \
+ APR ASM common port \n", __func__);
+ goto fail;
+ }
+ }
+
+ atomic_inc(&this_mmap.ref_cnt);
+ init_waitqueue_head(&ac->cmd_wait);
+ init_waitqueue_head(&ac->time_wait);
+ atomic_set(&ac->time_flag, 1);
+ mutex_init(&ac->cmd_lock);
+ for (lcnt = 0; lcnt <= OUT; lcnt++) {
+ mutex_init(&ac->port[lcnt].lock);
+ spin_lock_init(&ac->port[lcnt].dsp_lock);
+ }
+ atomic_set(&ac->cmd_state, 0);
+
+ pr_debug("%s: session[%d]\n", __func__, ac->session);
+
+ return ac;
+fail:
+ q6asm_audio_client_free(ac);
+ return NULL;
+fail_session:
+ kfree(ac);
+ return NULL;
+}
+
+int q6asm_audio_client_buf_alloc(unsigned int dir,
+ struct audio_client *ac,
+ unsigned int bufsz,
+ unsigned int bufcnt)
+{
+ int cnt = 0;
+ int rc = 0;
+ struct audio_buffer *buf;
+
+ if (!(ac) || ((dir != IN) && (dir != OUT)))
+ return -EINVAL;
+
+ pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n", __func__, ac->session,
+ bufsz, bufcnt);
+
+ if (ac->session <= 0 || ac->session > 8)
+ goto fail;
+
+ if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->port[dir].buf) {
+ pr_debug("%s: buffer already allocated\n", __func__);
+ return 0;
+ }
+ mutex_lock(&ac->cmd_lock);
+ buf = kzalloc(((sizeof(struct audio_buffer))*bufcnt),
+ GFP_KERNEL);
+
+ if (!buf) {
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+
+ ac->port[dir].buf = buf;
+
+ while (cnt < bufcnt) {
+ if (bufsz > 0) {
+ if (!buf[cnt].data) {
+ unsigned int flags = 0;
+ buf[cnt].phys =
+ allocate_contiguous_ebi_nomap(bufsz,
+ SZ_4K);
+ if (!buf[cnt].phys) {
+ pr_err("%s:Buf alloc failed "
+ " size=%d\n", __func__,
+ bufsz);
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+ flags = MSM_SUBSYSTEM_MAP_KADDR |
+ MSM_SUBSYSTEM_MAP_CACHED;
+ buf[cnt].mem_buffer =
+ msm_subsystem_map_buffer(buf[cnt].phys,
+ bufsz, flags, NULL, 0);
+ if (IS_ERR(
+ (void *)buf[cnt].mem_buffer)) {
+ pr_err("%s:map_buffer failed,"
+ "error = %ld\n",
+ __func__, PTR_ERR((void *)buf[cnt].mem_buffer));
+ goto fail;
+ }
+ buf[cnt].data =
+ buf[cnt].mem_buffer->vaddr;
+ if (!buf[cnt].data) {
+ pr_err("%s:invalid vaddr,"
+ " iomap failed\n", __func__);
+ goto fail;
+ }
+ buf[cnt].used = 1;
+ buf[cnt].size = bufsz;
+ buf[cnt].actual_size = bufsz;
+ pr_debug("%s data[%p]phys[%p][%p]"
+ "mem_buffer[%p]\n",
+ __func__,
+ (void *)buf[cnt].data,
+ (void *)buf[cnt].phys,
+ (void *)&buf[cnt].phys,
+ (void *)buf[cnt].mem_buffer);
+ cnt++;
+ }
+ }
+ }
+ ac->port[dir].max_buf_cnt = cnt;
+
+ mutex_unlock(&ac->cmd_lock);
+ rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt);
+ if (rc < 0) {
+ pr_err("%s:CMD Memory_map_regions failed\n", __func__);
+ goto fail;
+ }
+ }
+ return 0;
+fail:
+ q6asm_audio_client_buf_free(dir, ac);
+ return -EINVAL;
+}
+
+int q6asm_audio_client_buf_alloc_contiguous(unsigned int dir,
+ struct audio_client *ac,
+ unsigned int bufsz,
+ unsigned int bufcnt)
+{
+ int cnt = 0;
+ int rc = 0;
+ struct audio_buffer *buf;
+
+ if (!(ac) || ((dir != IN) && (dir != OUT)))
+ return -EINVAL;
+
+ pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n",
+ __func__, ac->session,
+ bufsz, bufcnt);
+
+ if (ac->session <= 0 || ac->session > 8)
+ goto fail;
+
+ if (ac->port[dir].buf) {
+ pr_debug("%s: buffer already allocated\n", __func__);
+ return 0;
+ }
+ mutex_lock(&ac->cmd_lock);
+ buf = kzalloc(((sizeof(struct audio_buffer))*bufcnt),
+ GFP_KERNEL);
+
+ if (!buf) {
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+
+ ac->port[dir].buf = buf;
+
+ buf[0].data = dma_alloc_coherent(NULL, bufsz * bufcnt,
+ &buf[0].phys, GFP_KERNEL);
+ buf[0].used = dir ^ 1;
+ buf[0].size = bufsz;
+ buf[0].actual_size = bufsz;
+ cnt = 1;
+ while (cnt < bufcnt) {
+ if (bufsz > 0) {
+ buf[cnt].data = buf[0].data + (cnt * bufsz);
+ buf[cnt].phys = buf[0].phys + (cnt * bufsz);
+ if (!buf[cnt].data) {
+ pr_err("%s Buf alloc failed\n",
+ __func__);
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+ buf[cnt].used = dir ^ 1;
+ buf[cnt].size = bufsz;
+ buf[cnt].actual_size = bufsz;
+ pr_debug("%s data[%p]phys[%p][%p]\n", __func__,
+ (void *)buf[cnt].data,
+ (void *)buf[cnt].phys,
+ (void *)&buf[cnt].phys);
+ }
+ cnt++;
+ }
+ ac->port[dir].max_buf_cnt = cnt;
+ mutex_unlock(&ac->cmd_lock);
+ rc = q6asm_memory_map(ac, buf[0].phys, dir, bufsz, cnt);
+ if (rc < 0) {
+ pr_err("%s:CMD Memory_map_regions failed\n", __func__);
+ goto fail;
+ }
+ return 0;
+fail:
+ q6asm_audio_client_buf_free_contiguous(dir, ac);
+ return -EINVAL;
+}
+
+static int32_t q6asm_mmapcallback(struct apr_client_data *data, void *priv)
+{
+ uint32_t token;
+ uint32_t *payload = data->payload;
+
+ if (data->opcode == RESET_EVENTS) {
+ pr_debug("%s: Reset event is received: %d %d apr[%p]\n",
+ __func__,
+ data->reset_event,
+ data->reset_proc,
+ this_mmap.apr);
+ apr_reset(this_mmap.apr);
+ this_mmap.apr = NULL;
+ atomic_set(&this_mmap.cmd_state, 0);
+ return 0;
+ }
+
+ pr_debug("%s:ptr0[0x%x]ptr1[0x%x]opcode[0x%x]"
+ "token[0x%x]payload_s[%d] src[%d] dest[%d]\n", __func__,
+ payload[0], payload[1], data->opcode, data->token,
+ data->payload_size, data->src_port, data->dest_port);
+
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ token = data->token;
+ switch (payload[0]) {
+ case ASM_SESSION_CMD_MEMORY_MAP:
+ case ASM_SESSION_CMD_MEMORY_UNMAP:
+ case ASM_SESSION_CMD_MEMORY_MAP_REGIONS:
+ case ASM_SESSION_CMD_MEMORY_UNMAP_REGIONS:
+ pr_debug("%s:command[0x%x]success [0x%x]\n",
+ __func__, payload[0], payload[1]);
+ if (atomic_read(&this_mmap.cmd_state)) {
+ atomic_set(&this_mmap.cmd_state, 0);
+ wake_up(&this_mmap.cmd_wait);
+ }
+ break;
+ default:
+ pr_debug("%s:command[0x%x] not expecting rsp\n",
+ __func__, payload[0]);
+ break;
+ }
+ }
+ return 0;
+}
+
+
+static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
+{
+ int i = 0;
+ struct audio_client *ac = (struct audio_client *)priv;
+ uint32_t token;
+ unsigned long dsp_flags;
+ uint32_t *payload;
+
+
+ if ((ac == NULL) || (data == NULL)) {
+ pr_err("ac or priv NULL\n");
+ return -EINVAL;
+ }
+ if (ac->session <= 0 || ac->session > 8) {
+ pr_err("%s:Session ID is invalid, session = %d\n", __func__,
+ ac->session);
+ return -EINVAL;
+ }
+
+ payload = data->payload;
+
+ if (data->opcode == RESET_EVENTS) {
+ pr_debug("q6asm_callback: Reset event is received: %d %d apr[%p]\n",
+ data->reset_event, data->reset_proc, ac->apr);
+ apr_reset(ac->apr);
+ return 0;
+ }
+
+ pr_debug("%s: session[%d]opcode[0x%x] \
+ token[0x%x]payload_s[%d] src[%d] dest[%d]\n", __func__,
+ ac->session, data->opcode,
+ data->token, data->payload_size, data->src_port,
+ data->dest_port);
+
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ token = data->token;
+ switch (payload[0]) {
+ case ASM_STREAM_CMD_SET_PP_PARAMS:
+#ifdef CONFIG_MSM8X60_RTAC
+ if (rtac_make_asm_callback(ac->session, payload,
+ data->payload_size))
+ break;
+#endif
+ case ASM_SESSION_CMD_PAUSE:
+ case ASM_DATA_CMD_EOS:
+ case ASM_STREAM_CMD_CLOSE:
+ case ASM_STREAM_CMD_FLUSH:
+ case ASM_SESSION_CMD_RUN:
+ case ASM_SESSION_CMD_REGISTER_FOR_TX_OVERFLOW_EVENTS:
+ case ASM_STREAM_CMD_FLUSH_READBUFS:
+ pr_debug("%s:Payload = [0x%x]\n", __func__, payload[0]);
+ if (token != ac->session) {
+ pr_err("%s:Invalid session[%d] rxed expected[%d]",
+ __func__, token, ac->session);
+ return -EINVAL;
+ }
+ case ASM_STREAM_CMD_OPEN_READ:
+ case ASM_STREAM_CMD_OPEN_WRITE:
+ case ASM_STREAM_CMD_OPEN_READWRITE:
+ case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
+ case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+ if (atomic_read(&ac->cmd_state)) {
+ atomic_set(&ac->cmd_state, 0);
+ wake_up(&ac->cmd_wait);
+ }
+ if (ac->cb)
+ ac->cb(data->opcode, data->token,
+ (uint32_t *)data->payload, ac->priv);
+ break;
+ default:
+ pr_debug("%s:command[0x%x] not expecting rsp\n",
+ __func__, payload[0]);
+ break;
+ }
+ return 0;
+ }
+
+ switch (data->opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE:{
+ struct audio_port_data *port = &ac->port[IN];
+ pr_debug("%s: Rxed opcode[0x%x] status[0x%x] token[%d]",
+ __func__, payload[0], payload[1],
+ data->token);
+ if (ac->io_mode == SYNC_IO_MODE) {
+ if (port->buf == NULL) {
+ pr_err("%s: Unexpected Write Done\n",
+ __func__);
+ return -EINVAL;
+ }
+ spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+ if (port->buf[data->token].phys !=
+ payload[0]) {
+ pr_err("Buf expected[%p]rxed[%p]\n",\
+ (void *)port->buf[data->token].phys,\
+ (void *)payload[0]);
+ spin_unlock_irqrestore(&port->dsp_lock,
+ dsp_flags);
+ return -EINVAL;
+ }
+ token = data->token;
+ port->buf[token].used = 1;
+ spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+ for (i = 0; i < port->max_buf_cnt; i++)
+ pr_debug("%d ", port->buf[i].used);
+
+ }
+ break;
+ }
+#ifdef CONFIG_MSM8X60_RTAC
+ case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
+ rtac_make_asm_callback(ac->session, payload,
+ data->payload_size);
+ break;
+#endif
+ case ASM_DATA_EVENT_READ_DONE:{
+
+ struct audio_port_data *port = &ac->port[OUT];
+
+ pr_debug("%s:R-D: status=%d buff_add=%x act_size=%d offset=%d\n",
+ __func__, payload[READDONE_IDX_STATUS],
+ payload[READDONE_IDX_BUFFER],
+ payload[READDONE_IDX_SIZE],
+ payload[READDONE_IDX_OFFSET]);
+ pr_debug("%s:R-D:msw_ts=%d lsw_ts=%d flags=%d id=%d num=%d\n",
+ __func__, payload[READDONE_IDX_MSW_TS],
+ payload[READDONE_IDX_LSW_TS],
+ payload[READDONE_IDX_FLAGS],
+ payload[READDONE_IDX_ID],
+ payload[READDONE_IDX_NUMFRAMES]);
+
+ if (ac->io_mode == SYNC_IO_MODE) {
+ if (port->buf == NULL) {
+ pr_err("%s: Unexpected Write Done\n", __func__);
+ return -EINVAL;
+ }
+ spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+ token = data->token;
+ port->buf[token].used = 0;
+ if (port->buf[token].phys !=
+ payload[READDONE_IDX_BUFFER]) {
+ pr_err("Buf expected[%p]rxed[%p]\n",\
+ (void *)port->buf[token].phys,\
+ (void *)payload[READDONE_IDX_BUFFER]);
+ spin_unlock_irqrestore(&port->dsp_lock,
+ dsp_flags);
+ break;
+ }
+ port->buf[token].actual_size =
+ payload[READDONE_IDX_SIZE];
+ spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+ }
+ break;
+ }
+ case ASM_DATA_EVENT_EOS:
+ case ASM_DATA_CMDRSP_EOS:
+ pr_debug("%s:EOS ACK received: rxed opcode[0x%x]\n",
+ __func__, data->opcode);
+ break;
+ case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
+ break;
+ case ASM_SESSION_EVENT_TX_OVERFLOW:
+ pr_err("ASM_SESSION_EVENT_TX_OVERFLOW\n");
+ break;
+ case ASM_SESSION_CMDRSP_GET_SESSION_TIME:
+ pr_debug("%s: ASM_SESSION_CMDRSP_GET_SESSION_TIME, "
+ "payload[0] = %d, payload[1] = %d, "
+ "payload[2] = %d\n", __func__,
+ payload[0], payload[1], payload[2]);
+ ac->time_stamp = (uint64_t)(((uint64_t)payload[1] << 32) |
+ payload[2]);
+ if (atomic_read(&ac->time_flag)) {
+ atomic_set(&ac->time_flag, 0);
+ wake_up(&ac->time_wait);
+ }
+ break;
+ case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+ pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
+ "payload[0] = %d, payload[1] = %d, "
+ "payload[2] = %d, payload[3] = %d\n", __func__,
+ payload[0], payload[1], payload[2],
+ payload[3]);
+ break;
+ }
+ if (ac->cb)
+ ac->cb(data->opcode, data->token,
+ data->payload, ac->priv);
+
+ return 0;
+}
+
+void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac, uint32_t *size,
+ uint32_t *index)
+{
+ void *data;
+ unsigned char idx;
+ struct audio_port_data *port;
+
+ if (!ac || ((dir != IN) && (dir != OUT)))
+ return NULL;
+
+ if (ac->io_mode == SYNC_IO_MODE) {
+ port = &ac->port[dir];
+
+ mutex_lock(&port->lock);
+ idx = port->cpu_buf;
+ if (port->buf == NULL) {
+ pr_debug("%s:Buffer pointer null\n", __func__);
+ return NULL;
+ }
+ /* dir 0: used = 0 means buf in use
+ dir 1: used = 1 means buf in use */
+ if (port->buf[idx].used == dir) {
+ /* To make it more robust, we could loop and get the
+ next avail buf, its risky though */
+ pr_debug("%s:Next buf idx[0x%x] not available,\
+ dir[%d]\n", __func__, idx, dir);
+ mutex_unlock(&port->lock);
+ return NULL;
+ }
+ *size = port->buf[idx].actual_size;
+ *index = port->cpu_buf;
+ data = port->buf[idx].data;
+ pr_debug("%s:session[%d]index[%d] data[%p]size[%d]\n",
+ __func__,
+ ac->session,
+ port->cpu_buf,
+ data, *size);
+ /* By default increase the cpu_buf cnt
+ user accesses this function,increase cpu
+ buf(to avoid another api)*/
+ port->buf[idx].used = dir;
+ port->cpu_buf = ((port->cpu_buf + 1) & (port->max_buf_cnt - 1));
+ mutex_unlock(&port->lock);
+ return data;
+ }
+ return NULL;
+}
+
+int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac)
+{
+ int ret = -1;
+ struct audio_port_data *port;
+ uint32_t idx;
+
+ if (!ac || (dir != OUT))
+ return ret;
+
+ if (ac->io_mode == SYNC_IO_MODE) {
+ port = &ac->port[dir];
+
+ mutex_lock(&port->lock);
+ idx = port->dsp_buf;
+
+ if (port->buf[idx].used == (dir ^ 1)) {
+ /* To make it more robust, we could loop and get the
+ next avail buf, its risky though */
+ pr_err("Next buf idx[0x%x] not available, dir[%d]\n",
+ idx, dir);
+ mutex_unlock(&port->lock);
+ return ret;
+ }
+ pr_debug("%s: session[%d]dsp_buf=%d cpu_buf=%d\n", __func__,
+ ac->session, port->dsp_buf, port->cpu_buf);
+ ret = ((port->dsp_buf != port->cpu_buf) ? 0 : -1);
+ mutex_unlock(&port->lock);
+ }
+ return ret;
+}
+
+static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg)
+{
+ pr_debug("%s:session=%d pkt size=%d cmd_flg=%d\n", __func__, pkt_size,
+ cmd_flg, ac->session);
+ mutex_lock(&ac->cmd_lock);
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+ APR_HDR_LEN(sizeof(struct apr_hdr)),\
+ APR_PKT_VER);
+ hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
+ hdr->src_domain = APR_DOMAIN_APPS;
+ hdr->dest_svc = APR_SVC_ASM;
+ hdr->dest_domain = APR_DOMAIN_ADSP;
+ hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
+ hdr->dest_port = ((ac->session << 8) & 0xFF00) | 0x01;
+ if (cmd_flg) {
+ hdr->token = ac->session;
+ atomic_set(&ac->cmd_state, 1);
+ }
+ hdr->pkt_size = pkt_size;
+ mutex_unlock(&ac->cmd_lock);
+ return;
+}
+
+static void q6asm_add_mmaphdr(struct apr_hdr *hdr, uint32_t pkt_size,
+ uint32_t cmd_flg)
+{
+ pr_debug("%s:pkt size=%d cmd_flg=%d\n", __func__, pkt_size, cmd_flg);
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ hdr->src_port = 0;
+ hdr->dest_port = 0;
+ if (cmd_flg) {
+ hdr->token = 0;
+ atomic_set(&this_mmap.cmd_state, 1);
+ }
+ hdr->pkt_size = pkt_size;
+ return;
+}
+
+int q6asm_open_read(struct audio_client *ac,
+ uint32_t format)
+{
+ int rc = 0x00;
+ struct asm_stream_cmd_open_read open;
+
+ if ((ac == NULL) || (ac->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s:session[%d]", __func__, ac->session);
+
+ q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ;
+ /* Stream prio : High, provide meta info with encoded frames */
+ open.src_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+
+ open.pre_proc_top = get_asm_topology();
+ if (open.pre_proc_top == 0)
+ open.pre_proc_top = DEFAULT_POPP_TOPOLOGY;
+
+ switch (format) {
+ case FORMAT_LINEAR_PCM:
+ open.uMode = STREAM_PRIORITY_HIGH;
+ open.format = LINEAR_PCM;
+ break;
+ case FORMAT_MPEG4_AAC:
+ open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+ open.format = MPEG4_AAC;
+ break;
+ case FORMAT_V13K:
+ open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+ open.format = V13K_FS;
+ break;
+ case FORMAT_EVRC:
+ open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+ open.format = EVRC_FS;
+ break;
+ case FORMAT_AMRNB:
+ open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+ open.format = AMRNB_FS;
+ break;
+ default:
+ pr_err("Invalid format[%d]\n", format);
+ goto fail_cmd;
+ }
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("open failed op[0x%x]rc[%d]\n", \
+ open.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for OPEN_WRITE rc[%d]\n", __func__,
+ rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_open_write(struct audio_client *ac, uint32_t format)
+{
+ int rc = 0x00;
+ struct asm_stream_cmd_open_write open;
+
+ if ((ac == NULL) || (ac->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d] wr_format[0x%x]", __func__, ac->session,
+ format);
+
+ q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE;
+ open.uMode = STREAM_PRIORITY_HIGH;
+ /* source endpoint : matrix */
+ open.sink_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+ open.stream_handle = 0x00;
+
+ open.post_proc_top = get_asm_topology();
+ if (open.post_proc_top == 0)
+ open.post_proc_top = DEFAULT_POPP_TOPOLOGY;
+
+ switch (format) {
+ case FORMAT_LINEAR_PCM:
+ open.format = LINEAR_PCM;
+ break;
+ case FORMAT_MPEG4_AAC:
+ open.format = MPEG4_AAC;
+ break;
+ case FORMAT_WMA_V9:
+ open.format = WMA_V9;
+ break;
+ case FORMAT_WMA_V10PRO:
+ open.format = WMA_V10PRO;
+ break;
+ default:
+ pr_err("%s: Invalid format[%d]\n", __func__, format);
+ goto fail_cmd;
+ }
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("%s: open failed op[0x%x]rc[%d]\n", \
+ __func__, open.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for OPEN_WRITE rc[%d]\n", __func__,
+ rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_open_read_write(struct audio_client *ac,
+ uint32_t rd_format,
+ uint32_t wr_format)
+{
+ int rc = 0x00;
+ struct asm_stream_cmd_open_read_write open;
+
+ if ((ac == NULL) || (ac->apr == NULL)) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]", __func__, ac->session);
+ pr_debug("wr_format[0x%x]rd_format[0x%x]",
+ wr_format, rd_format);
+
+ q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_READWRITE;
+
+ open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_NORMAL |
+ SR_CM_NOTIFY_ENABLE;
+ /* source endpoint : matrix */
+ open.post_proc_top = get_asm_topology();
+ if (open.post_proc_top == 0)
+ open.post_proc_top = DEFAULT_POPP_TOPOLOGY;
+
+ switch (wr_format) {
+ case FORMAT_LINEAR_PCM:
+ open.write_format = LINEAR_PCM;
+ break;
+ case FORMAT_MPEG4_AAC:
+ open.write_format = MPEG4_AAC;
+ break;
+ case FORMAT_WMA_V9:
+ open.write_format = WMA_V9;
+ break;
+ case FORMAT_WMA_V10PRO:
+ open.write_format = WMA_V10PRO;
+ break;
+ default:
+ pr_err("Invalid format[%d]\n", wr_format);
+ goto fail_cmd;
+ }
+
+ switch (rd_format) {
+ case FORMAT_LINEAR_PCM:
+ open.read_format = LINEAR_PCM;
+ break;
+ case FORMAT_MPEG4_AAC:
+ open.read_format = MPEG4_AAC;
+ break;
+ case FORMAT_V13K:
+ open.read_format = V13K_FS;
+ break;
+ case FORMAT_EVRC:
+ open.read_format = EVRC_FS;
+ break;
+ case FORMAT_AMRNB:
+ open.read_format = AMRNB_FS;
+ break;
+ default:
+ pr_err("Invalid format[%d]\n", rd_format);
+ goto fail_cmd;
+ }
+ pr_debug("%s:rdformat[0x%x]wrformat[0x%x]\n", __func__,
+ open.read_format, open.write_format);
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("open failed op[0x%x]rc[%d]\n", \
+ open.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout. waited for OPEN_WRITE rc[%d]\n", rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_run(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts)
+{
+ struct asm_stream_cmd_run run;
+ int rc;
+ if (!ac || ac->apr == NULL) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s session[%d]", __func__, ac->session);
+ q6asm_add_hdr(ac, &run.hdr, sizeof(run), TRUE);
+
+ run.hdr.opcode = ASM_SESSION_CMD_RUN;
+ run.flags = flags;
+ run.msw_ts = msw_ts;
+ run.lsw_ts = lsw_ts;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
+ if (rc < 0) {
+ pr_err("Commmand run failed[%d]", rc);
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout. waited for run success rc[%d]", rc);
+ goto fail_cmd;
+ }
+
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts)
+{
+ struct asm_stream_cmd_run run;
+ int rc;
+ if (!ac || ac->apr == NULL) {
+ pr_err("%s:APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("session[%d]", ac->session);
+ q6asm_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE);
+
+ run.hdr.opcode = ASM_SESSION_CMD_RUN;
+ run.flags = flags;
+ run.msw_ts = msw_ts;
+ run.lsw_ts = lsw_ts;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
+ if (rc < 0) {
+ pr_err("%s:Commmand run failed[%d]", __func__, rc);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
+ uint32_t frames_per_buf,
+ uint32_t sample_rate, uint32_t channels,
+ uint32_t bit_rate, uint32_t mode, uint32_t format)
+{
+ struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+ int rc = 0;
+
+ pr_debug("%s:session[%d]frames[%d]SR[%d]ch[%d]bitrate[%d]mode[%d]"
+ "format[%d]", __func__, ac->session, frames_per_buf,
+ sample_rate, channels, bit_rate, mode, format);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+ enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+ enc_cfg.enc_blk.frames_per_buf = frames_per_buf;
+ enc_cfg.enc_blk.format_id = MPEG4_AAC;
+ enc_cfg.enc_blk.cfg_size = sizeof(struct asm_aac_read_cfg);
+ enc_cfg.enc_blk.cfg.aac.bitrate = bit_rate;
+ enc_cfg.enc_blk.cfg.aac.enc_mode = mode;
+ enc_cfg.enc_blk.cfg.aac.format = format;
+ enc_cfg.enc_blk.cfg.aac.ch_cfg = channels;
+ enc_cfg.enc_blk.cfg.aac.sample_rate = sample_rate;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout. waited for FORMAT_UPDATE\n");
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels)
+{
+ struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+
+ int rc = 0;
+
+ pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
+ ac->session, rate, channels);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+ enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+ enc_cfg.enc_blk.frames_per_buf = 1;
+ enc_cfg.enc_blk.format_id = LINEAR_PCM;
+ enc_cfg.enc_blk.cfg_size = sizeof(struct asm_pcm_cfg);
+ enc_cfg.enc_blk.cfg.pcm.ch_cfg = channels;
+ enc_cfg.enc_blk.cfg.pcm.bits_per_sample = 16;
+ enc_cfg.enc_blk.cfg.pcm.sample_rate = rate;
+ enc_cfg.enc_blk.cfg.pcm.is_signed = 1;
+ enc_cfg.enc_blk.cfg.pcm.interleaved = 1;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("Comamnd open failed\n");
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout opcode[0x%x] ", enc_cfg.hdr.opcode);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_enable_sbrps(struct audio_client *ac,
+ uint32_t sbr_ps_enable)
+{
+ struct asm_stream_cmd_encdec_sbr sbrps;
+
+ int rc = 0;
+
+ pr_debug("%s: Session %d\n", __func__, ac->session);
+
+ q6asm_add_hdr(ac, &sbrps.hdr, sizeof(sbrps), TRUE);
+
+ sbrps.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ sbrps.param_id = ASM_ENABLE_SBR_PS;
+ sbrps.param_size = sizeof(struct asm_sbr_ps);
+ sbrps.sbr_ps.enable = sbr_ps_enable;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &sbrps);
+ if (rc < 0) {
+ pr_err("Command opcode[0x%x]paramid[0x%x] failed\n",
+ ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+ ASM_ENABLE_SBR_PS);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout opcode[0x%x] ", sbrps.hdr.opcode);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
+ uint16_t min_rate, uint16_t max_rate,
+ uint16_t reduced_rate_level, uint16_t rate_modulation_cmd)
+{
+ struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+ int rc = 0;
+
+ pr_debug("%s:session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] \
+ reduced_rate_level[0x%4x]rate_modulation_cmd[0x%4x]", __func__,
+ ac->session, frames_per_buf, min_rate, max_rate,
+ reduced_rate_level, rate_modulation_cmd);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+
+ enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+ enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+
+ enc_cfg.enc_blk.frames_per_buf = frames_per_buf;
+ enc_cfg.enc_blk.format_id = V13K_FS;
+ enc_cfg.enc_blk.cfg_size = sizeof(struct asm_qcelp13_read_cfg);
+ enc_cfg.enc_blk.cfg.qcelp13.min_rate = min_rate;
+ enc_cfg.enc_blk.cfg.qcelp13.max_rate = max_rate;
+ enc_cfg.enc_blk.cfg.qcelp13.reduced_rate_level = reduced_rate_level;
+ enc_cfg.enc_blk.cfg.qcelp13.rate_modulation_cmd = rate_modulation_cmd;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout. waited for FORMAT_UPDATE\n");
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_evrc(struct audio_client *ac, uint32_t frames_per_buf,
+ uint16_t min_rate, uint16_t max_rate,
+ uint16_t rate_modulation_cmd)
+{
+ struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+ int rc = 0;
+
+ pr_debug("%s:session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] \
+ rate_modulation_cmd[0x%4x]", __func__, ac->session,
+ frames_per_buf, min_rate, max_rate, rate_modulation_cmd);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+
+ enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+ enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+
+ enc_cfg.enc_blk.frames_per_buf = frames_per_buf;
+ enc_cfg.enc_blk.format_id = EVRC_FS;
+ enc_cfg.enc_blk.cfg_size = sizeof(struct asm_evrc_read_cfg);
+ enc_cfg.enc_blk.cfg.evrc.min_rate = min_rate;
+ enc_cfg.enc_blk.cfg.evrc.max_rate = max_rate;
+ enc_cfg.enc_blk.cfg.evrc.rate_modulation_cmd = rate_modulation_cmd;
+ enc_cfg.enc_blk.cfg.evrc.reserved = 0;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout. waited for FORMAT_UPDATE\n");
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_amrnb(struct audio_client *ac, uint32_t frames_per_buf,
+ uint16_t band_mode, uint16_t dtx_enable)
+{
+ struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+ int rc = 0;
+
+ pr_debug("%s:session[%d]frames[%d]band_mode[0x%4x]dtx_enable[0x%4x]",
+ __func__, ac->session, frames_per_buf, band_mode, dtx_enable);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+
+ enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+ enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+
+ enc_cfg.enc_blk.frames_per_buf = frames_per_buf;
+ enc_cfg.enc_blk.format_id = AMRNB_FS;
+ enc_cfg.enc_blk.cfg_size = sizeof(struct asm_amrnb_read_cfg);
+ enc_cfg.enc_blk.cfg.amrnb.mode = band_mode;
+ enc_cfg.enc_blk.cfg.amrnb.dtx_mode = dtx_enable;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout. waited for FORMAT_UPDATE\n");
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_media_format_block_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels)
+{
+ struct asm_stream_media_format_update fmt;
+ int rc = 0;
+
+ pr_debug("%s:session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
+ channels);
+
+ q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+ fmt.format = LINEAR_PCM;
+ fmt.cfg_size = sizeof(struct asm_pcm_cfg);
+ fmt.write_cfg.pcm_cfg.ch_cfg = channels;
+ fmt.write_cfg.pcm_cfg.bits_per_sample = 16;
+ fmt.write_cfg.pcm_cfg.sample_rate = rate;
+ fmt.write_cfg.pcm_cfg.is_signed = 1;
+ fmt.write_cfg.pcm_cfg.interleaved = 1;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s:Comamnd open failed\n", __func__);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_media_format_block_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg)
+{
+ struct asm_stream_media_format_update fmt;
+ int rc = 0;
+
+ pr_debug("%s:session[%d]rate[%d]ch[%d]\n", __func__, ac->session,
+ cfg->sample_rate, cfg->ch_cfg);
+
+ q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+ fmt.format = MPEG4_AAC;
+ fmt.cfg_size = sizeof(struct asm_aac_cfg);
+ fmt.write_cfg.aac_cfg.format = cfg->format;
+ fmt.write_cfg.aac_cfg.aot = cfg->aot;
+ fmt.write_cfg.aac_cfg.ep_config = cfg->ep_config;
+ fmt.write_cfg.aac_cfg.section_data_resilience =
+ cfg->section_data_resilience;
+ fmt.write_cfg.aac_cfg.scalefactor_data_resilience =
+ cfg->scalefactor_data_resilience;
+ fmt.write_cfg.aac_cfg.spectral_data_resilience =
+ cfg->spectral_data_resilience;
+ fmt.write_cfg.aac_cfg.ch_cfg = cfg->ch_cfg;
+ fmt.write_cfg.aac_cfg.sample_rate = cfg->sample_rate;
+ pr_info("%s:format=%x cfg_size=%d aac-cfg=%x aot=%d ch=%d sr=%d\n",
+ __func__, fmt.format, fmt.cfg_size,
+ fmt.write_cfg.aac_cfg.format,
+ fmt.write_cfg.aac_cfg.aot,
+ fmt.write_cfg.aac_cfg.ch_cfg,
+ fmt.write_cfg.aac_cfg.sample_rate);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s:Comamnd open failed\n", __func__);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_media_format_block_wma(struct audio_client *ac,
+ void *cfg)
+{
+ struct asm_stream_media_format_update fmt;
+ struct asm_wma_cfg *wma_cfg = (struct asm_wma_cfg *)cfg;
+ int rc = 0;
+
+ pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d],\
+ balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x]\n",
+ ac->session, wma_cfg->format_tag, wma_cfg->sample_rate,
+ wma_cfg->ch_cfg, wma_cfg->avg_bytes_per_sec,
+ wma_cfg->block_align, wma_cfg->valid_bits_per_sample,
+ wma_cfg->ch_mask, wma_cfg->encode_opt);
+
+ q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+ fmt.format = WMA_V9;
+ fmt.cfg_size = sizeof(struct asm_wma_cfg);
+ fmt.write_cfg.wma_cfg.format_tag = wma_cfg->format_tag;
+ fmt.write_cfg.wma_cfg.ch_cfg = wma_cfg->ch_cfg;
+ fmt.write_cfg.wma_cfg.sample_rate = wma_cfg->sample_rate;
+ fmt.write_cfg.wma_cfg.avg_bytes_per_sec = wma_cfg->avg_bytes_per_sec;
+ fmt.write_cfg.wma_cfg.block_align = wma_cfg->block_align;
+ fmt.write_cfg.wma_cfg.valid_bits_per_sample =
+ wma_cfg->valid_bits_per_sample;
+ fmt.write_cfg.wma_cfg.ch_mask = wma_cfg->ch_mask;
+ fmt.write_cfg.wma_cfg.encode_opt = wma_cfg->encode_opt;
+ fmt.write_cfg.wma_cfg.adv_encode_opt = 0;
+ fmt.write_cfg.wma_cfg.adv_encode_opt2 = 0;
+ fmt.write_cfg.wma_cfg.drc_peak_ref = 0;
+ fmt.write_cfg.wma_cfg.drc_peak_target = 0;
+ fmt.write_cfg.wma_cfg.drc_ave_ref = 0;
+ fmt.write_cfg.wma_cfg.drc_ave_target = 0;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s:Comamnd open failed\n", __func__);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_media_format_block_wmapro(struct audio_client *ac,
+ void *cfg)
+{
+ struct asm_stream_media_format_update fmt;
+ struct asm_wmapro_cfg *wmapro_cfg = (struct asm_wmapro_cfg *)cfg;
+ int rc = 0;
+
+ pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d],"
+ "balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x],\
+ adv_enc_opt[0x%4x], adv_enc_opt2[0x%8x]\n",
+ ac->session, wmapro_cfg->format_tag, wmapro_cfg->sample_rate,
+ wmapro_cfg->ch_cfg, wmapro_cfg->avg_bytes_per_sec,
+ wmapro_cfg->block_align, wmapro_cfg->valid_bits_per_sample,
+ wmapro_cfg->ch_mask, wmapro_cfg->encode_opt,
+ wmapro_cfg->adv_encode_opt, wmapro_cfg->adv_encode_opt2);
+
+ q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+ fmt.format = WMA_V10PRO;
+ fmt.cfg_size = sizeof(struct asm_wmapro_cfg);
+ fmt.write_cfg.wmapro_cfg.format_tag = wmapro_cfg->format_tag;
+ fmt.write_cfg.wmapro_cfg.ch_cfg = wmapro_cfg->ch_cfg;
+ fmt.write_cfg.wmapro_cfg.sample_rate = wmapro_cfg->sample_rate;
+ fmt.write_cfg.wmapro_cfg.avg_bytes_per_sec =
+ wmapro_cfg->avg_bytes_per_sec;
+ fmt.write_cfg.wmapro_cfg.block_align = wmapro_cfg->block_align;
+ fmt.write_cfg.wmapro_cfg.valid_bits_per_sample =
+ wmapro_cfg->valid_bits_per_sample;
+ fmt.write_cfg.wmapro_cfg.ch_mask = wmapro_cfg->ch_mask;
+ fmt.write_cfg.wmapro_cfg.encode_opt = wmapro_cfg->encode_opt;
+ fmt.write_cfg.wmapro_cfg.adv_encode_opt = wmapro_cfg->adv_encode_opt;
+ fmt.write_cfg.wmapro_cfg.adv_encode_opt2 = wmapro_cfg->adv_encode_opt2;
+ fmt.write_cfg.wmapro_cfg.drc_peak_ref = 0;
+ fmt.write_cfg.wmapro_cfg.drc_peak_target = 0;
+ fmt.write_cfg.wmapro_cfg.drc_ave_ref = 0;
+ fmt.write_cfg.wmapro_cfg.drc_ave_target = 0;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s:Comamnd open failed\n", __func__);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_memory_map(struct audio_client *ac, uint32_t buf_add, int dir,
+ uint32_t bufsz, uint32_t bufcnt)
+{
+ struct asm_stream_cmd_memory_map mem_map;
+ int rc = 0;
+
+ if (!ac || ac->apr == NULL || this_mmap.apr == NULL) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+
+ pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+ mem_map.hdr.opcode = ASM_SESSION_CMD_MEMORY_MAP;
+
+ mem_map.buf_add = buf_add;
+ mem_map.buf_size = bufsz * bufcnt;
+ mem_map.mempool_id = 0; /* EBI */
+ mem_map.reserved = 0;
+
+ q6asm_add_mmaphdr(&mem_map.hdr,
+ sizeof(struct asm_stream_cmd_memory_map), TRUE);
+
+ pr_debug("buf add[%x] buf_add_parameter[%x]\n",
+ mem_map.buf_add, buf_add);
+
+ rc = apr_send_pkt(this_mmap.apr, (uint32_t *) &mem_map);
+ if (rc < 0) {
+ pr_err("mem_map op[0x%x]rc[%d]\n",
+ mem_map.hdr.opcode, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(this_mmap.cmd_wait,
+ (atomic_read(&this_mmap.cmd_state) == 0), 5 * HZ);
+ if (!rc) {
+ pr_err("timeout. waited for memory_map\n");
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_memory_unmap(struct audio_client *ac, uint32_t buf_add, int dir)
+{
+ struct asm_stream_cmd_memory_unmap mem_unmap;
+ int rc = 0;
+
+ if (!ac || ac->apr == NULL || this_mmap.apr == NULL) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+ q6asm_add_mmaphdr(&mem_unmap.hdr,
+ sizeof(struct asm_stream_cmd_memory_unmap), TRUE);
+ mem_unmap.hdr.opcode = ASM_SESSION_CMD_MEMORY_UNMAP;
+ mem_unmap.buf_add = buf_add;
+
+ rc = apr_send_pkt(this_mmap.apr, (uint32_t *) &mem_unmap);
+ if (rc < 0) {
+ pr_err("mem_unmap op[0x%x]rc[%d]\n",
+ mem_unmap.hdr.opcode, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(this_mmap.cmd_wait,
+ (atomic_read(&this_mmap.cmd_state) == 0), 5 * HZ);
+ if (!rc) {
+ pr_err("timeout. waited for memory_map\n");
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
+int q6asm_set_lrgain(struct audio_client *ac, int left_gain, int right_gain)
+{
+ void *vol_cmd = NULL;
+ void *payload = NULL;
+ struct asm_pp_params_command *cmd = NULL;
+ struct asm_lrchannel_gain_params *lrgain = NULL;
+ int sz = 0;
+ int rc = 0;
+
+ sz = sizeof(struct asm_pp_params_command) +
+ + sizeof(struct asm_lrchannel_gain_params);
+ vol_cmd = kzalloc(sz, GFP_KERNEL);
+ if (vol_cmd == NULL) {
+ pr_err("%s[%d]: Mem alloc failed\n", __func__, ac->session);
+ rc = -EINVAL;
+ return rc;
+ }
+ cmd = (struct asm_pp_params_command *)vol_cmd;
+ q6asm_add_hdr_async(ac, &cmd->hdr, sz, TRUE);
+ cmd->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS;
+ cmd->payload = NULL;
+ cmd->payload_size = sizeof(struct asm_pp_param_data_hdr) +
+ sizeof(struct asm_lrchannel_gain_params);
+ cmd->params.module_id = VOLUME_CONTROL_MODULE_ID;
+ cmd->params.param_id = L_R_CHANNEL_GAIN_PARAM_ID;
+ cmd->params.param_size = sizeof(struct asm_lrchannel_gain_params);
+ cmd->params.reserved = 0;
+
+ payload = (u8 *)(vol_cmd + sizeof(struct asm_pp_params_command));
+ lrgain = (struct asm_lrchannel_gain_params *)payload;
+
+ lrgain->left_gain = left_gain;
+ lrgain->right_gain = right_gain;
+ rc = apr_send_pkt(ac->apr, (uint32_t *) vol_cmd);
+ if (rc < 0) {
+ pr_err("%s: Volume Command failed\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout in sending volume command to apr\n",
+ __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ kfree(vol_cmd);
+ return rc;
+}
+
+static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
+ uint32_t bufsz, uint32_t bufcnt)
+{
+ struct asm_stream_cmd_memory_map_regions *mmap_regions = NULL;
+ struct asm_memory_map_regions *mregions = NULL;
+ struct audio_port_data *port = NULL;
+ struct audio_buffer *ab = NULL;
+ void *mmap_region_cmd = NULL;
+ void *payload = NULL;
+ int rc = 0;
+ int i = 0;
+ int cmd_size = 0;
+
+ if (!ac || ac->apr == NULL || this_mmap.apr == NULL) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+ cmd_size = sizeof(struct asm_stream_cmd_memory_map_regions)
+ + sizeof(struct asm_memory_map_regions) * bufcnt;
+
+ mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+ mmap_regions = (struct asm_stream_cmd_memory_map_regions *)
+ mmap_region_cmd;
+ q6asm_add_mmaphdr(&mmap_regions->hdr, cmd_size, TRUE);
+ mmap_regions->hdr.opcode = ASM_SESSION_CMD_MEMORY_MAP_REGIONS;
+ mmap_regions->mempool_id = 0;
+ mmap_regions->nregions = bufcnt & 0x00ff;
+ pr_debug("map_regions->nregions = %d\n", mmap_regions->nregions);
+ payload = ((u8 *) mmap_region_cmd +
+ sizeof(struct asm_stream_cmd_memory_map_regions));
+ mregions = (struct asm_memory_map_regions *)payload;
+
+ port = &ac->port[dir];
+ for (i = 0; i < bufcnt; i++) {
+ ab = &port->buf[i];
+ mregions->phys = ab->phys;
+ mregions->buf_size = ab->size;
+ ++mregions;
+ }
+
+ rc = apr_send_pkt(this_mmap.apr, (uint32_t *) mmap_region_cmd);
+ if (rc < 0) {
+ pr_err("mmap_regions op[0x%x]rc[%d]\n",
+ mmap_regions->hdr.opcode, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(this_mmap.cmd_wait,
+ (atomic_read(&this_mmap.cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout. waited for memory_map\n");
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ kfree(mmap_region_cmd);
+ return rc;
+}
+
+static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir,
+ uint32_t bufsz, uint32_t bufcnt)
+{
+ struct asm_stream_cmd_memory_unmap_regions *unmap_regions = NULL;
+ struct asm_memory_unmap_regions *mregions = NULL;
+ struct audio_port_data *port = NULL;
+ struct audio_buffer *ab = NULL;
+ void *unmap_region_cmd = NULL;
+ void *payload = NULL;
+ int rc = 0;
+ int i = 0;
+ int cmd_size = 0;
+
+ if (!ac || ac->apr == NULL || this_mmap.apr == NULL) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+ cmd_size = sizeof(struct asm_stream_cmd_memory_unmap_regions) +
+ sizeof(struct asm_memory_unmap_regions) * bufcnt;
+
+ unmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+ unmap_regions = (struct asm_stream_cmd_memory_unmap_regions *)
+ unmap_region_cmd;
+ q6asm_add_mmaphdr(&unmap_regions->hdr, cmd_size, TRUE);
+ unmap_regions->hdr.opcode = ASM_SESSION_CMD_MEMORY_UNMAP_REGIONS;
+ unmap_regions->nregions = bufcnt & 0x00ff;
+ pr_debug("unmap_regions->nregions = %d\n", unmap_regions->nregions);
+ payload = ((u8 *) unmap_region_cmd +
+ sizeof(struct asm_stream_cmd_memory_unmap_regions));
+ mregions = (struct asm_memory_unmap_regions *)payload;
+ port = &ac->port[dir];
+ for (i = 0; i < bufcnt; i++) {
+ ab = &port->buf[i];
+ mregions->phys = ab->phys;
+ ++mregions;
+ }
+
+ rc = apr_send_pkt(this_mmap.apr, (uint32_t *) unmap_region_cmd);
+ if (rc < 0) {
+ pr_err("mmap_regions op[0x%x]rc[%d]\n",
+ unmap_regions->hdr.opcode, rc);
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(this_mmap.cmd_wait,
+ (atomic_read(&this_mmap.cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout. waited for memory_unmap\n");
+ goto fail_cmd;
+ }
+ rc = 0;
+
+fail_cmd:
+ kfree(unmap_region_cmd);
+ return rc;
+}
+
+int q6asm_set_mute(struct audio_client *ac, int muteflag)
+{
+ void *vol_cmd = NULL;
+ void *payload = NULL;
+ struct asm_pp_params_command *cmd = NULL;
+ struct asm_mute_params *mute = NULL;
+ int sz = 0;
+ int rc = 0;
+
+ sz = sizeof(struct asm_pp_params_command) +
+ + sizeof(struct asm_mute_params);
+ vol_cmd = kzalloc(sz, GFP_KERNEL);
+ if (vol_cmd == NULL) {
+ pr_err("%s[%d]: Mem alloc failed\n", __func__, ac->session);
+ rc = -EINVAL;
+ return rc;
+ }
+ cmd = (struct asm_pp_params_command *)vol_cmd;
+ q6asm_add_hdr_async(ac, &cmd->hdr, sz, TRUE);
+ cmd->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS;
+ cmd->payload = NULL;
+ cmd->payload_size = sizeof(struct asm_pp_param_data_hdr) +
+ sizeof(struct asm_mute_params);
+ cmd->params.module_id = VOLUME_CONTROL_MODULE_ID;
+ cmd->params.param_id = MUTE_CONFIG_PARAM_ID;
+ cmd->params.param_size = sizeof(struct asm_mute_params);
+ cmd->params.reserved = 0;
+
+ payload = (u8 *)(vol_cmd + sizeof(struct asm_pp_params_command));
+ mute = (struct asm_mute_params *)payload;
+
+ mute->muteflag = muteflag;
+ rc = apr_send_pkt(ac->apr, (uint32_t *) vol_cmd);
+ if (rc < 0) {
+ pr_err("%s: Mute Command failed\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout in sending mute command to apr\n",
+ __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ kfree(vol_cmd);
+ return rc;
+}
+
+int q6asm_set_volume(struct audio_client *ac, int volume)
+{
+ void *vol_cmd = NULL;
+ void *payload = NULL;
+ struct asm_pp_params_command *cmd = NULL;
+ struct asm_master_gain_params *mgain = NULL;
+ int sz = 0;
+ int rc = 0;
+
+ sz = sizeof(struct asm_pp_params_command) +
+ + sizeof(struct asm_master_gain_params);
+ vol_cmd = kzalloc(sz, GFP_KERNEL);
+ if (vol_cmd == NULL) {
+ pr_err("%s[%d]: Mem alloc failed\n", __func__, ac->session);
+ rc = -EINVAL;
+ return rc;
+ }
+ cmd = (struct asm_pp_params_command *)vol_cmd;
+ q6asm_add_hdr_async(ac, &cmd->hdr, sz, TRUE);
+ cmd->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS;
+ cmd->payload = NULL;
+ cmd->payload_size = sizeof(struct asm_pp_param_data_hdr) +
+ sizeof(struct asm_master_gain_params);
+ cmd->params.module_id = VOLUME_CONTROL_MODULE_ID;
+ cmd->params.param_id = MASTER_GAIN_PARAM_ID;
+ cmd->params.param_size = sizeof(struct asm_master_gain_params);
+ cmd->params.reserved = 0;
+
+ payload = (u8 *)(vol_cmd + sizeof(struct asm_pp_params_command));
+ mgain = (struct asm_master_gain_params *)payload;
+
+ mgain->master_gain = volume;
+ mgain->padding = 0x00;
+ rc = apr_send_pkt(ac->apr, (uint32_t *) vol_cmd);
+ if (rc < 0) {
+ pr_err("%s: Volume Command failed\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout in sending volume command to apr\n",
+ __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ kfree(vol_cmd);
+ return rc;
+}
+
+int q6asm_set_softpause(struct audio_client *ac,
+ struct asm_softpause_params *pause_param)
+{
+ void *vol_cmd = NULL;
+ void *payload = NULL;
+ struct asm_pp_params_command *cmd = NULL;
+ struct asm_softpause_params *params = NULL;
+ int sz = 0;
+ int rc = 0;
+
+ sz = sizeof(struct asm_pp_params_command) +
+ + sizeof(struct asm_softpause_params);
+ vol_cmd = kzalloc(sz, GFP_KERNEL);
+ if (vol_cmd == NULL) {
+ pr_err("%s[%d]: Mem alloc failed\n", __func__, ac->session);
+ rc = -EINVAL;
+ return rc;
+ }
+ cmd = (struct asm_pp_params_command *)vol_cmd;
+ q6asm_add_hdr_async(ac, &cmd->hdr, sz, TRUE);
+ cmd->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS;
+ cmd->payload = NULL;
+ cmd->payload_size = sizeof(struct asm_pp_param_data_hdr) +
+ sizeof(struct asm_softpause_params);
+ cmd->params.module_id = VOLUME_CONTROL_MODULE_ID;
+ cmd->params.param_id = SOFT_PAUSE_PARAM_ID;
+ cmd->params.param_size = sizeof(struct asm_softpause_params);
+ cmd->params.reserved = 0;
+
+ payload = (u8 *)(vol_cmd + sizeof(struct asm_pp_params_command));
+ params = (struct asm_softpause_params *)payload;
+
+ params->enable = pause_param->enable;
+ params->period = pause_param->period;
+ params->step = pause_param->step;
+ params->rampingcurve = pause_param->rampingcurve;
+ pr_debug("%s: soft Pause Command: enable = %d, period = %d,"
+ "step = %d, curve = %d\n", __func__, params->enable,
+ params->period, params->step, params->rampingcurve);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) vol_cmd);
+ if (rc < 0) {
+ pr_err("%s: Volume Command(soft_pause) failed\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout in sending volume command(soft_pause)"
+ "to apr\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ kfree(vol_cmd);
+ return rc;
+}
+
+int q6asm_equalizer(struct audio_client *ac, void *eq)
+{
+ void *eq_cmd = NULL;
+ void *payload = NULL;
+ struct asm_pp_params_command *cmd = NULL;
+ struct asm_equalizer_params *equalizer = NULL;
+ struct msm_audio_eq_stream_config *eq_params = NULL;
+ int i = 0;
+ int sz = 0;
+ int rc = 0;
+
+ sz = sizeof(struct asm_pp_params_command) +
+ + sizeof(struct asm_equalizer_params);
+ eq_cmd = kzalloc(sz, GFP_KERNEL);
+ if (eq_cmd == NULL) {
+ pr_err("%s[%d]: Mem alloc failed\n", __func__, ac->session);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ eq_params = (struct msm_audio_eq_stream_config *) eq;
+ cmd = (struct asm_pp_params_command *)eq_cmd;
+ q6asm_add_hdr(ac, &cmd->hdr, sz, TRUE);
+ cmd->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS;
+ cmd->payload = NULL;
+ cmd->payload_size = sizeof(struct asm_pp_param_data_hdr) +
+ sizeof(struct asm_equalizer_params);
+ cmd->params.module_id = EQUALIZER_MODULE_ID;
+ cmd->params.param_id = EQUALIZER_PARAM_ID;
+ cmd->params.param_size = sizeof(struct asm_equalizer_params);
+ cmd->params.reserved = 0;
+ payload = (u8 *)(eq_cmd + sizeof(struct asm_pp_params_command));
+ equalizer = (struct asm_equalizer_params *)payload;
+
+ equalizer->enable = eq_params->enable;
+ equalizer->num_bands = eq_params->num_bands;
+ pr_debug("%s: enable:%d numbands:%d\n", __func__, eq_params->enable,
+ eq_params->num_bands);
+ for (i = 0; i < eq_params->num_bands; i++) {
+ equalizer->eq_bands[i].band_idx =
+ eq_params->eq_bands[i].band_idx;
+ equalizer->eq_bands[i].filter_type =
+ eq_params->eq_bands[i].filter_type;
+ equalizer->eq_bands[i].center_freq_hz =
+ eq_params->eq_bands[i].center_freq_hz;
+ equalizer->eq_bands[i].filter_gain =
+ eq_params->eq_bands[i].filter_gain;
+ equalizer->eq_bands[i].q_factor =
+ eq_params->eq_bands[i].q_factor;
+ pr_debug("%s: filter_type:%u bandnum:%d\n", __func__,
+ eq_params->eq_bands[i].filter_type, i);
+ pr_debug("%s: center_freq_hz:%u bandnum:%d\n", __func__,
+ eq_params->eq_bands[i].center_freq_hz, i);
+ pr_debug("%s: filter_gain:%d bandnum:%d\n", __func__,
+ eq_params->eq_bands[i].filter_gain, i);
+ pr_debug("%s: q_factor:%d bandnum:%d\n", __func__,
+ eq_params->eq_bands[i].q_factor, i);
+ }
+ rc = apr_send_pkt(ac->apr, (uint32_t *) eq_cmd);
+ if (rc < 0) {
+ pr_err("%s: Equalizer Command failed\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout in sending equalizer command to apr\n",
+ __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = 0;
+fail_cmd:
+ kfree(eq_cmd);
+ return rc;
+}
+
+int q6asm_read(struct audio_client *ac)
+{
+ struct asm_stream_cmd_read read;
+ struct audio_buffer *ab;
+ int dsp_buf;
+ struct audio_port_data *port;
+ int rc;
+ if (!ac || ac->apr == NULL) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ if (ac->io_mode == SYNC_IO_MODE) {
+ port = &ac->port[OUT];
+
+ q6asm_add_hdr(ac, &read.hdr, sizeof(read), FALSE);
+
+ mutex_lock(&port->lock);
+
+ dsp_buf = port->dsp_buf;
+ ab = &port->buf[dsp_buf];
+
+ pr_debug("%s:session[%d]dsp-buf[%d][%p]cpu_buf[%d][%p]\n",
+ __func__,
+ ac->session,
+ dsp_buf,
+ (void *)port->buf[dsp_buf].data,
+ port->cpu_buf,
+ (void *)port->buf[port->cpu_buf].phys);
+
+ read.hdr.opcode = ASM_DATA_CMD_READ;
+ read.buf_add = ab->phys;
+ read.buf_size = ab->size;
+ read.uid = port->dsp_buf;
+ read.hdr.token = port->dsp_buf;
+
+ port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
+ mutex_unlock(&port->lock);
+ pr_debug("%s:buf add[0x%x] token[%d] uid[%d]\n", __func__,
+ read.buf_add,
+ read.hdr.token,
+ read.uid);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+ if (rc < 0) {
+ pr_err("read op[0x%x]rc[%d]\n", read.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ return 0;
+ }
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_read_nolock(struct audio_client *ac)
+{
+ struct asm_stream_cmd_read read;
+ struct audio_buffer *ab;
+ int dsp_buf;
+ struct audio_port_data *port;
+ int rc;
+ if (!ac || ac->apr == NULL) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ if (ac->io_mode == SYNC_IO_MODE) {
+ port = &ac->port[OUT];
+
+ q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
+
+
+ dsp_buf = port->dsp_buf;
+ ab = &port->buf[dsp_buf];
+
+ pr_debug("%s:session[%d]dsp-buf[%d][%p]cpu_buf[%d][%p]\n",
+ __func__,
+ ac->session,
+ dsp_buf,
+ (void *)port->buf[dsp_buf].data,
+ port->cpu_buf,
+ (void *)port->buf[port->cpu_buf].phys);
+
+ read.hdr.opcode = ASM_DATA_CMD_READ;
+ read.buf_add = ab->phys;
+ read.buf_size = ab->size;
+ read.uid = port->dsp_buf;
+ read.hdr.token = port->dsp_buf;
+
+ port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
+ pr_debug("%s:buf add[0x%x] token[%d] uid[%d]\n", __func__,
+ read.buf_add,
+ read.hdr.token,
+ read.uid);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+ if (rc < 0) {
+ pr_err("read op[0x%x]rc[%d]\n", read.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ return 0;
+ }
+fail_cmd:
+ return -EINVAL;
+}
+
+
+static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg)
+{
+ pr_debug("session=%d pkt size=%d cmd_flg=%d\n", pkt_size, cmd_flg,
+ ac->session);
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+ APR_HDR_LEN(sizeof(struct apr_hdr)),\
+ APR_PKT_VER);
+ hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
+ hdr->src_domain = APR_DOMAIN_APPS;
+ hdr->dest_svc = APR_SVC_ASM;
+ hdr->dest_domain = APR_DOMAIN_ADSP;
+ hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
+ hdr->dest_port = ((ac->session << 8) & 0xFF00) | 0x01;
+ if (cmd_flg) {
+ hdr->token = ac->session;
+ atomic_set(&ac->cmd_state, 1);
+ }
+ hdr->pkt_size = pkt_size;
+ return;
+}
+
+int q6asm_async_write(struct audio_client *ac,
+ struct audio_aio_write_param *param)
+{
+ int rc = 0;
+ struct asm_stream_cmd_write write;
+
+ if (!ac || ac->apr == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ q6asm_add_hdr_async(ac, &write.hdr, sizeof(write), FALSE);
+
+ /* Pass physical address as token for AIO scheme */
+ write.hdr.token = param->uid;
+ write.hdr.opcode = ASM_DATA_CMD_WRITE;
+ write.buf_add = param->paddr;
+ write.avail_bytes = param->len;
+ write.uid = param->uid;
+ write.msw_ts = param->msw_ts;
+ write.lsw_ts = param->lsw_ts;
+ /* Use 0xFF00 for disabling timestamps */
+ if (param->flags == 0xFF00)
+ write.uflags = (0x00000000 | (param->flags & 0x800000FF));
+ else
+ write.uflags = (0x80000000 | param->flags);
+
+ pr_debug("%s: session[%d] bufadd[0x%x]len[0x%x]", __func__, ac->session,
+ write.buf_add, write.avail_bytes);
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
+ if (rc < 0) {
+ pr_debug("[%s] write op[0x%x]rc[%d]\n", __func__,
+ write.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_async_read(struct audio_client *ac,
+ struct audio_aio_read_param *param)
+{
+ int rc = 0;
+ struct asm_stream_cmd_read read;
+
+ if (!ac || ac->apr == NULL) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
+
+ /* Pass physical address as token for AIO scheme */
+ read.hdr.token = param->paddr;
+ read.hdr.opcode = ASM_DATA_CMD_READ;
+ read.buf_add = param->paddr;
+ read.buf_size = param->len;
+ read.uid = param->uid;
+
+ pr_debug("%s: session[%d] bufadd[0x%x]len[0x%x]", __func__, ac->session,
+ read.buf_add, read.buf_size);
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+ if (rc < 0) {
+ pr_debug("[%s] read op[0x%x]rc[%d]\n", __func__,
+ read.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+ uint32_t lsw_ts, uint32_t flags)
+{
+ int rc = 0;
+ struct asm_stream_cmd_write write;
+ struct audio_port_data *port;
+ struct audio_buffer *ab;
+ int dsp_buf = 0;
+
+ if (!ac || ac->apr == NULL) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
+ if (ac->io_mode == SYNC_IO_MODE) {
+ port = &ac->port[IN];
+
+ q6asm_add_hdr(ac, &write.hdr, sizeof(write),
+ FALSE);
+ mutex_lock(&port->lock);
+
+ dsp_buf = port->dsp_buf;
+ ab = &port->buf[dsp_buf];
+
+ write.hdr.token = port->dsp_buf;
+ write.hdr.opcode = ASM_DATA_CMD_WRITE;
+ write.buf_add = ab->phys;
+ write.avail_bytes = len;
+ write.uid = port->dsp_buf;
+ write.msw_ts = msw_ts;
+ write.lsw_ts = lsw_ts;
+ /* Use 0xFF00 for disabling timestamps */
+ if (flags == 0xFF00)
+ write.uflags = (0x00000000 | (flags & 0x800000FF));
+ else
+ write.uflags = (0x80000000 | flags);
+ port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
+
+ pr_debug("%s:ab->phys[0x%x]bufadd[0x%x]token[0x%x]buf_id[0x%x]"
+ , __func__,
+ ab->phys,
+ write.buf_add,
+ write.hdr.token,
+ write.uid);
+ mutex_unlock(&port->lock);
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
+ if (rc < 0) {
+ pr_err("write op[0x%x]rc[%d]\n", write.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ pr_debug("%s: WRITE SUCCESS\n", __func__);
+ return 0;
+ }
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+ uint32_t lsw_ts, uint32_t flags)
+{
+ int rc = 0;
+ struct asm_stream_cmd_write write;
+ struct audio_port_data *port;
+ struct audio_buffer *ab;
+ int dsp_buf = 0;
+
+ if (!ac || ac->apr == NULL) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
+ if (ac->io_mode == SYNC_IO_MODE) {
+ port = &ac->port[IN];
+
+ q6asm_add_hdr_async(ac, &write.hdr, sizeof(write),
+ FALSE);
+
+ dsp_buf = port->dsp_buf;
+ ab = &port->buf[dsp_buf];
+
+ write.hdr.token = port->dsp_buf;
+ write.hdr.opcode = ASM_DATA_CMD_WRITE;
+ write.buf_add = ab->phys;
+ write.avail_bytes = len;
+ write.uid = port->dsp_buf;
+ write.msw_ts = msw_ts;
+ write.lsw_ts = lsw_ts;
+ /* Use 0xFF00 for disabling timestamps */
+ if (flags == 0xFF00)
+ write.uflags = (0x00000000 | (flags & 0x800000FF));
+ else
+ write.uflags = (0x80000000 | flags);
+ port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
+
+ pr_debug("%s:ab->phys[0x%x]bufadd[0x%x]token[0x%x]buf_id[0x%x]"
+ , __func__,
+ ab->phys,
+ write.buf_add,
+ write.hdr.token,
+ write.uid);
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
+ if (rc < 0) {
+ pr_err("write op[0x%x]rc[%d]\n", write.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ pr_debug("%s: WRITE SUCCESS\n", __func__);
+ return 0;
+ }
+fail_cmd:
+ return -EINVAL;
+}
+
+uint64_t q6asm_get_session_time(struct audio_client *ac)
+{
+ struct apr_hdr hdr;
+ int rc;
+
+ if (!ac || ac->apr == NULL) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
+ hdr.opcode = ASM_SESSION_CMD_GET_SESSION_TIME;
+ atomic_set(&ac->time_flag, 1);
+
+ pr_debug("%s: session[%d]opcode[0x%x]\n", __func__,
+ ac->session,
+ hdr.opcode);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
+ if (rc < 0) {
+ pr_err("Commmand 0x%x failed\n", hdr.opcode);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->time_wait,
+ (atomic_read(&ac->time_flag) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout in getting session time from DSP\n",
+ __func__);
+ goto fail_cmd;
+ }
+ return ac->time_stamp;
+
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_cmd(struct audio_client *ac, int cmd)
+{
+ struct apr_hdr hdr;
+ int rc;
+ atomic_t *state;
+ int cnt = 0;
+
+ if (!ac || ac->apr == NULL) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
+ switch (cmd) {
+ case CMD_PAUSE:
+ pr_debug("%s:CMD_PAUSE\n", __func__);
+ hdr.opcode = ASM_SESSION_CMD_PAUSE;
+ state = &ac->cmd_state;
+ break;
+ case CMD_FLUSH:
+ pr_debug("%s:CMD_FLUSH\n", __func__);
+ hdr.opcode = ASM_STREAM_CMD_FLUSH;
+ state = &ac->cmd_state;
+ break;
+ case CMD_OUT_FLUSH:
+ pr_debug("%s:CMD_OUT_FLUSH\n", __func__);
+ hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
+ state = &ac->cmd_state;
+ break;
+ case CMD_EOS:
+ pr_debug("%s:CMD_EOS\n", __func__);
+ hdr.opcode = ASM_DATA_CMD_EOS;
+ atomic_set(&ac->cmd_state, 0);
+ state = &ac->cmd_state;
+ break;
+ case CMD_CLOSE:
+ pr_debug("%s:CMD_CLOSE\n", __func__);
+ hdr.opcode = ASM_STREAM_CMD_CLOSE;
+ state = &ac->cmd_state;
+ break;
+ default:
+ pr_err("Invalid format[%d]\n", cmd);
+ goto fail_cmd;
+ }
+ pr_debug("%s:session[%d]opcode[0x%x] ", __func__,
+ ac->session,
+ hdr.opcode);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
+ if (rc < 0) {
+ pr_err("Commmand 0x%x failed\n", hdr.opcode);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait, (atomic_read(state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout. waited for response opcode[0x%x]\n",
+ hdr.opcode);
+ goto fail_cmd;
+ }
+ if (cmd == CMD_FLUSH)
+ q6asm_reset_buf_state(ac);
+ if (cmd == CMD_CLOSE) {
+ /* check if DSP return all buffers */
+ if (ac->port[IN].buf) {
+ for (cnt = 0; cnt < ac->port[IN].max_buf_cnt;
+ cnt++) {
+ if (ac->port[IN].buf[cnt].used == IN) {
+ pr_debug("Write Buf[%d] not returned\n",
+ cnt);
+ }
+ }
+ }
+ if (ac->port[OUT].buf) {
+ for (cnt = 0; cnt < ac->port[OUT].max_buf_cnt; cnt++) {
+ if (ac->port[OUT].buf[cnt].used == OUT) {
+ pr_debug("Read Buf[%d] not returned\n",
+ cnt);
+ }
+ }
+ }
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
+{
+ struct apr_hdr hdr;
+ int rc;
+
+ if (!ac || ac->apr == NULL) {
+ pr_err("%s:APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ q6asm_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE);
+ switch (cmd) {
+ case CMD_PAUSE:
+ pr_debug("%s:CMD_PAUSE\n", __func__);
+ hdr.opcode = ASM_SESSION_CMD_PAUSE;
+ break;
+ case CMD_EOS:
+ pr_debug("%s:CMD_EOS\n", __func__);
+ hdr.opcode = ASM_DATA_CMD_EOS;
+ break;
+ default:
+ pr_err("%s:Invalid format[%d]\n", __func__, cmd);
+ goto fail_cmd;
+ }
+ pr_debug("%s:session[%d]opcode[0x%x] ", __func__,
+ ac->session,
+ hdr.opcode);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
+ if (rc < 0) {
+ pr_err("%s:Commmand 0x%x failed\n", __func__, hdr.opcode);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+static void q6asm_reset_buf_state(struct audio_client *ac)
+{
+ int cnt = 0;
+ int loopcnt = 0;
+ struct audio_port_data *port = NULL;
+
+ if (ac->io_mode == SYNC_IO_MODE) {
+ mutex_lock(&ac->cmd_lock);
+ for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
+ port = &ac->port[loopcnt];
+ cnt = port->max_buf_cnt - 1;
+ port->dsp_buf = 0;
+ port->cpu_buf = 0;
+ while (cnt >= 0) {
+ if (!port->buf)
+ continue;
+ port->buf[cnt].used = 1;
+ cnt--;
+ }
+ }
+ mutex_unlock(&ac->cmd_lock);
+ }
+}
+
+int q6asm_reg_tx_overflow(struct audio_client *ac, uint16_t enable)
+{
+ struct asm_stream_cmd_reg_tx_overflow_event tx_overflow;
+ int rc;
+
+ if (!ac || ac->apr == NULL) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s:session[%d]enable[%d]\n", __func__,
+ ac->session, enable);
+ q6asm_add_hdr(ac, &tx_overflow.hdr, sizeof(tx_overflow), TRUE);
+
+ tx_overflow.hdr.opcode = \
+ ASM_SESSION_CMD_REGISTER_FOR_TX_OVERFLOW_EVENTS;
+ /* tx overflow event: enable */
+ tx_overflow.enable = enable;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &tx_overflow);
+ if (rc < 0) {
+ pr_err("tx overflow op[0x%x]rc[%d]\n", \
+ tx_overflow.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout. waited for tx overflow\n");
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+#ifdef CONFIG_MSM8X60_RTAC
+int q6asm_get_apr_service_id(int session_id)
+{
+ pr_debug("%s\n", __func__);
+
+ if (session_id < 0) {
+ pr_err("%s: invalid session_id = %d\n", __func__, session_id);
+ return -EINVAL;
+ }
+
+ return ((struct apr_svc *)session[session_id]->apr)->id;
+}
+#endif
+
+
+static int __init q6asm_init(void)
+{
+ pr_debug("%s\n", __func__);
+ init_waitqueue_head(&this_mmap.cmd_wait);
+ memset(session, 0, sizeof(session));
+ return 0;
+}
+
+device_initcall(q6asm_init);
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
new file mode 100644
index 0000000..28d1acf
--- /dev/null
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -0,0 +1,2089 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+#include "sound/apr_audio.h"
+#include "sound/q6afe.h"
+#include "q6voice.h"
+
+#define TIMEOUT_MS 3000
+
+#define CMD_STATUS_SUCCESS 0
+#define CMD_STATUS_FAIL 1
+
+#define VOC_PATH_PASSIVE 0
+#define VOC_PATH_FULL 1
+
+static struct voice_data voice;
+
+static int voice_send_enable_vocproc_cmd(struct voice_data *v);
+static int voice_send_netid_timing_cmd(struct voice_data *v);
+static int voice_send_attach_vocproc_cmd(struct voice_data *v);
+static int voice_send_set_device_cmd(struct voice_data *v);
+static int voice_send_disable_vocproc_cmd(struct voice_data *v);
+static int voice_send_vol_index_cmd(struct voice_data *v);
+
+static int32_t qdsp_mvm_callback(struct apr_client_data *data, void *priv);
+static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv);
+static int32_t qdsp_cvp_callback(struct apr_client_data *data, void *priv);
+
+static u16 voice_get_mvm_handle(struct voice_data *v)
+{
+ u16 mvm_handle = 0;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (v->voc_path == VOC_PATH_PASSIVE)
+ mvm_handle = v->mvm_passive_handle;
+ else
+ mvm_handle = v->mvm_full_handle;
+
+ pr_debug("%s: mvm_handle %d\n", __func__, mvm_handle);
+
+ return mvm_handle;
+}
+
+static void voice_set_mvm_handle(struct voice_data *v, u16 mvm_handle)
+{
+ pr_debug("%s: mvm_handle %d\n", __func__, mvm_handle);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return;
+ }
+
+ if (v->voc_path == VOC_PATH_PASSIVE)
+ v->mvm_passive_handle = mvm_handle;
+ else
+ v->mvm_full_handle = mvm_handle;
+}
+
+static u16 voice_get_cvs_handle(struct voice_data *v)
+{
+ u16 cvs_handle = 0;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (v->voc_path == VOC_PATH_PASSIVE)
+ cvs_handle = v->cvs_passive_handle;
+ else
+ cvs_handle = v->cvs_full_handle;
+
+ pr_debug("%s: cvs_handle %d\n", __func__, cvs_handle);
+
+ return cvs_handle;
+}
+
+static void voice_set_cvs_handle(struct voice_data *v, u16 cvs_handle)
+{
+ pr_debug("%s: cvs_handle %d\n", __func__, cvs_handle);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return;
+ }
+ if (v->voc_path == VOC_PATH_PASSIVE)
+ v->cvs_passive_handle = cvs_handle;
+ else
+ v->cvs_full_handle = cvs_handle;
+}
+
+static u16 voice_get_cvp_handle(struct voice_data *v)
+{
+ u16 cvp_handle = 0;
+
+ if (v->voc_path == VOC_PATH_PASSIVE)
+ cvp_handle = v->cvp_passive_handle;
+ else
+ cvp_handle = v->cvp_full_handle;
+
+ pr_debug("%s: cvp_handle %d\n", __func__, cvp_handle);
+
+ return cvp_handle;
+}
+
+static void voice_set_cvp_handle(struct voice_data *v, u16 cvp_handle)
+{
+ pr_debug("%s: cvp_handle %d\n", __func__, cvp_handle);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return;
+ }
+ if (v->voc_path == VOC_PATH_PASSIVE)
+ v->cvp_passive_handle = cvp_handle;
+ else
+ v->cvp_full_handle = cvp_handle;
+}
+
+static int voice_apr_register(struct voice_data *v)
+{
+ void *apr_mvm, *apr_cvs, *apr_cvp;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = v->apr_q6_mvm;
+ apr_cvs = v->apr_q6_cvs;
+ apr_cvp = v->apr_q6_cvp;
+
+ pr_debug("into voice_apr_register_callback\n");
+ /* register callback to APR */
+ if (apr_mvm == NULL) {
+ pr_debug("start to register MVM callback\n");
+
+ apr_mvm = apr_register("ADSP", "MVM",
+ qdsp_mvm_callback,
+ 0xFFFFFFFF, v);
+
+ if (apr_mvm == NULL) {
+ pr_err("Unable to register MVM\n");
+ goto err;
+ }
+ v->apr_q6_mvm = apr_mvm;
+ }
+
+ if (apr_cvs == NULL) {
+ pr_debug("start to register CVS callback\n");
+
+ apr_cvs = apr_register("ADSP", "CVS",
+ qdsp_cvs_callback,
+ 0xFFFFFFFF, v);
+
+ if (apr_cvs == NULL) {
+ pr_err("Unable to register CVS\n");
+ goto err;
+ }
+ v->apr_q6_cvs = apr_cvs;
+ }
+
+ if (apr_cvp == NULL) {
+ pr_debug("start to register CVP callback\n");
+
+ apr_cvp = apr_register("ADSP", "CVP",
+ qdsp_cvp_callback,
+ 0xFFFFFFFF, v);
+
+ if (apr_cvp == NULL) {
+ pr_err("Unable to register CVP\n");
+ goto err;
+ }
+ v->apr_q6_cvp = apr_cvp;
+ }
+ return 0;
+
+err:
+ if (v->apr_q6_cvs != NULL) {
+ apr_deregister(apr_cvs);
+ v->apr_q6_cvs = NULL;
+ }
+ if (v->apr_q6_mvm != NULL) {
+ apr_deregister(apr_mvm);
+ v->apr_q6_mvm = NULL;
+ }
+
+ return -ENODEV;
+}
+
+static int voice_create_mvm_cvs_session(struct voice_data *v)
+{
+ int ret = 0;
+ struct mvm_create_passive_ctl_session_cmd mvm_session_cmd;
+ struct cvs_create_passive_ctl_session_cmd cvs_session_cmd;
+ struct mvm_create_full_ctl_session_cmd mvm_full_ctl_cmd;
+ struct cvs_create_full_ctl_session_cmd cvs_full_ctl_cmd;
+ struct mvm_attach_stream_cmd attach_stream_cmd;
+ void *apr_mvm, *apr_cvs, *apr_cvp;
+ u16 mvm_handle, cvs_handle, cvp_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = v->apr_q6_mvm;
+ apr_cvs = v->apr_q6_cvs;
+ apr_cvp = v->apr_q6_cvp;
+
+ if (!apr_mvm || !apr_cvs || !apr_cvp) {
+ pr_err("%s: apr_mvm or apr_cvs or apr_cvp is NULL\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+ cvs_handle = voice_get_cvs_handle(v);
+ cvp_handle = voice_get_cvp_handle(v);
+
+ pr_debug("%s: mvm_hdl=%d, cvs_hdl=%d\n", __func__,
+ mvm_handle, cvs_handle);
+ /* send cmd to create mvm session and wait for response */
+
+ if (!mvm_handle) {
+ if (v->voc_path == VOC_PATH_PASSIVE) {
+ mvm_session_cmd.hdr.hdr_field = APR_HDR_FIELD(
+ APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_session_cmd.hdr.pkt_size = APR_PKT_SIZE(
+ APR_HDR_SIZE,
+ sizeof(mvm_session_cmd) -
+ APR_HDR_SIZE);
+ pr_debug("send mvm create session pkt size = %d\n",
+ mvm_session_cmd.hdr.pkt_size);
+ mvm_session_cmd.hdr.src_port = 0;
+ mvm_session_cmd.hdr.dest_port = 0;
+ mvm_session_cmd.hdr.token = 0;
+ mvm_session_cmd.hdr.opcode =
+ VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION;
+ v->mvm_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_mvm,
+ (uint32_t *) &mvm_session_cmd);
+ if (ret < 0) {
+ pr_err("Error sending MVM_CONTROL_SESSION\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ } else {
+ pr_debug("%s: creating MVM full ctrl\n", __func__);
+ mvm_full_ctl_cmd.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mvm_full_ctl_cmd.hdr.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_full_ctl_cmd) -
+ APR_HDR_SIZE);
+ mvm_full_ctl_cmd.hdr.src_port = 0;
+ mvm_full_ctl_cmd.hdr.dest_port = 0;
+ mvm_full_ctl_cmd.hdr.token = 0;
+ mvm_full_ctl_cmd.hdr.opcode =
+ VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION;
+ strncpy(mvm_full_ctl_cmd.mvm_session.name,
+ "default voip", 12);
+
+ v->mvm_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_mvm,
+ (uint32_t *) &mvm_full_ctl_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending MVM_CONTROL_SESSION\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ }
+ /* Get the created MVM handle. */
+ mvm_handle = voice_get_mvm_handle(v);
+ }
+ /* send cmd to create cvs session */
+ if (!cvs_handle) {
+ if (v->voc_path == VOC_PATH_PASSIVE) {
+ pr_debug("creating CVS passive session\n");
+
+ cvs_session_cmd.hdr.hdr_field = APR_HDR_FIELD(
+ APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_session_cmd.hdr.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_session_cmd) -
+ APR_HDR_SIZE);
+ cvs_session_cmd.hdr.src_port = 0;
+ cvs_session_cmd.hdr.dest_port = 0;
+ cvs_session_cmd.hdr.token = 0;
+ cvs_session_cmd.hdr.opcode =
+ VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION;
+ strncpy(cvs_session_cmd.cvs_session.name,
+ "default modem voice", 19);
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs,
+ (uint32_t *) &cvs_session_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending STREAM_CONTROL_SESSION\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ /* Get the created CVS handle. */
+ cvs_handle = voice_get_cvs_handle(v);
+
+ } else {
+ pr_debug("creating CVS full session\n");
+
+ cvs_full_ctl_cmd.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+
+ cvs_full_ctl_cmd.hdr.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_full_ctl_cmd) -
+ APR_HDR_SIZE);
+
+ cvs_full_ctl_cmd.hdr.src_port = 0;
+ cvs_full_ctl_cmd.hdr.dest_port = 0;
+ cvs_full_ctl_cmd.hdr.token = 0;
+ cvs_full_ctl_cmd.hdr.opcode =
+ VSS_ISTREAM_CMD_CREATE_FULL_CONTROL_SESSION;
+ cvs_full_ctl_cmd.cvs_session.direction = 2;
+ cvs_full_ctl_cmd.cvs_session.enc_media_type =
+ v->mvs_info.media_type;
+ cvs_full_ctl_cmd.cvs_session.dec_media_type =
+ v->mvs_info.media_type;
+ cvs_full_ctl_cmd.cvs_session.network_id =
+ v->mvs_info.network_type;
+ strncpy(cvs_full_ctl_cmd.cvs_session.name,
+ "default q6 voice", 16);
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs,
+ (uint32_t *) &cvs_full_ctl_cmd);
+
+ if (ret < 0) {
+ pr_err("%s: Err %d sending CREATE_FULL_CTRL\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ /* Get the created CVS handle. */
+ cvs_handle = voice_get_cvs_handle(v);
+
+ /* Attach MVM to CVS. */
+ pr_debug("Attach MVM to stream\n");
+
+ attach_stream_cmd.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ attach_stream_cmd.hdr.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(attach_stream_cmd) -
+ APR_HDR_SIZE);
+ attach_stream_cmd.hdr.src_port = 0;
+ attach_stream_cmd.hdr.dest_port = mvm_handle;
+ attach_stream_cmd.hdr.token = 0;
+ attach_stream_cmd.hdr.opcode =
+ VSS_IMVM_CMD_ATTACH_STREAM;
+ attach_stream_cmd.attach_stream.handle = cvs_handle;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm,
+ (uint32_t *) &attach_stream_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending ATTACH_STREAM\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ }
+ }
+ return 0;
+
+fail:
+ return -EINVAL;
+}
+
+static int voice_destroy_mvm_cvs_session(struct voice_data *v)
+{
+ int ret = 0;
+ struct mvm_detach_stream_cmd detach_stream;
+ struct apr_hdr mvm_destroy;
+ struct apr_hdr cvs_destroy;
+ void *apr_mvm, *apr_cvs;
+ u16 mvm_handle, cvs_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = v->apr_q6_mvm;
+ apr_cvs = v->apr_q6_cvs;
+
+ if (!apr_mvm || !apr_cvs) {
+ pr_err("%s: apr_mvm or apr_cvs is NULL\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+ cvs_handle = voice_get_cvs_handle(v);
+
+ /* MVM, CVS sessions are destroyed only for Full control sessions. */
+ if (v->voc_path == VOC_PATH_FULL) {
+ pr_debug("MVM detach stream\n");
+
+ /* Detach voice stream. */
+ detach_stream.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ detach_stream.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(detach_stream) - APR_HDR_SIZE);
+ detach_stream.hdr.src_port = 0;
+ detach_stream.hdr.dest_port = mvm_handle;
+ detach_stream.hdr.token = 0;
+ detach_stream.hdr.opcode = VSS_IMVM_CMD_DETACH_STREAM;
+ detach_stream.detach_stream.handle = cvs_handle;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &detach_stream);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending DETACH_STREAM\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait event timeout\n", __func__);
+ goto fail;
+ }
+ /* Destroy CVS. */
+ pr_debug("CVS destroy session\n");
+
+ cvs_destroy.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_destroy.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_destroy) - APR_HDR_SIZE);
+ cvs_destroy.src_port = 0;
+ cvs_destroy.dest_port = cvs_handle;
+ cvs_destroy.token = 0;
+ cvs_destroy.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_destroy);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending CVS DESTROY\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait event timeout\n", __func__);
+
+ goto fail;
+ }
+ cvs_handle = 0;
+ voice_set_cvs_handle(v, cvs_handle);
+
+ /* Destroy MVM. */
+ pr_debug("MVM destroy session\n");
+
+ mvm_destroy.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_destroy.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_destroy) - APR_HDR_SIZE);
+ mvm_destroy.src_port = 0;
+ mvm_destroy.dest_port = mvm_handle;
+ mvm_destroy.token = 0;
+ mvm_destroy.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_destroy);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending MVM DESTROY\n",
+ __func__, ret);
+
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait event timeout\n", __func__);
+
+ goto fail;
+ }
+ mvm_handle = 0;
+ voice_set_mvm_handle(v, mvm_handle);
+ }
+ return 0;
+fail:
+ return -EINVAL;
+}
+
+static int voice_send_tty_mode_cmd(struct voice_data *v)
+{
+ int tty_mode = 0;
+ int ret = 0;
+ struct mvm_set_tty_mode_cmd mvm_tty_mode_cmd;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = v->apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ if (tty_mode) {
+ /* send tty mode cmd to mvm */
+ mvm_tty_mode_cmd.hdr.hdr_field = APR_HDR_FIELD(
+ APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_tty_mode_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_tty_mode_cmd) -
+ APR_HDR_SIZE);
+ pr_debug("pkt size = %d\n", mvm_tty_mode_cmd.hdr.pkt_size);
+ mvm_tty_mode_cmd.hdr.src_port = 0;
+ mvm_tty_mode_cmd.hdr.dest_port = mvm_handle;
+ mvm_tty_mode_cmd.hdr.token = 0;
+ mvm_tty_mode_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_TTY_MODE;
+ mvm_tty_mode_cmd.tty_mode.mode = tty_mode;
+ pr_debug("tty mode =%d\n", mvm_tty_mode_cmd.tty_mode.mode);
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_tty_mode_cmd);
+ if (ret < 0) {
+ pr_err("Fail: sending VSS_ISTREAM_CMD_SET_TTY_MODE\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ }
+ return 0;
+fail:
+ return -EINVAL;
+}
+
+static int voice_config_cvs_vocoder(struct voice_data *v)
+{
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+ /* Set media type. */
+ struct cvs_set_media_type_cmd cvs_set_media_cmd;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = v->apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ cvs_set_media_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_set_media_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_set_media_cmd) - APR_HDR_SIZE);
+ cvs_set_media_cmd.hdr.src_port = 0;
+ cvs_set_media_cmd.hdr.dest_port = cvs_handle;
+ cvs_set_media_cmd.hdr.token = 0;
+ cvs_set_media_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_MEDIA_TYPE;
+ cvs_set_media_cmd.media_type.tx_media_id = v->mvs_info.media_type;
+ cvs_set_media_cmd.media_type.rx_media_id = v->mvs_info.media_type;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_media_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_MEDIA_TYPE\n",
+ __func__, ret);
+
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ goto fail;
+ }
+ /* Set encoder properties. */
+ switch (v->mvs_info.media_type) {
+ case VSS_MEDIA_ID_EVRC_MODEM: {
+ struct cvs_set_cdma_enc_minmax_rate_cmd cvs_set_cdma_rate;
+
+ pr_debug("Setting EVRC min-max rate\n");
+
+ cvs_set_cdma_rate.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_set_cdma_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_set_cdma_rate) - APR_HDR_SIZE);
+ cvs_set_cdma_rate.hdr.src_port = 0;
+ cvs_set_cdma_rate.hdr.dest_port = cvs_handle;
+ cvs_set_cdma_rate.hdr.token = 0;
+ cvs_set_cdma_rate.hdr.opcode =
+ VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE;
+ cvs_set_cdma_rate.cdma_rate.min_rate = v->mvs_info.rate;
+ cvs_set_cdma_rate.cdma_rate.max_rate = v->mvs_info.rate;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_cdma_rate);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_EVRC_MINMAX_RATE\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ goto fail;
+ }
+ break;
+ }
+ case VSS_MEDIA_ID_AMR_NB_MODEM: {
+ struct cvs_set_amr_enc_rate_cmd cvs_set_amr_rate;
+ struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
+
+ pr_debug("Setting AMR rate\n");
+
+ cvs_set_amr_rate.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_set_amr_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_set_amr_rate) - APR_HDR_SIZE);
+ cvs_set_amr_rate.hdr.src_port = 0;
+ cvs_set_amr_rate.hdr.dest_port = cvs_handle;
+ cvs_set_amr_rate.hdr.token = 0;
+ cvs_set_amr_rate.hdr.opcode =
+ VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE;
+ cvs_set_amr_rate.amr_rate.mode = v->mvs_info.rate;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amr_rate);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_AMR_RATE\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ /* Disable DTX */
+ pr_debug("Disabling DTX\n");
+
+ cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_set_dtx) - APR_HDR_SIZE);
+ cvs_set_dtx.hdr.src_port = 0;
+ cvs_set_dtx.hdr.dest_port = cvs_handle;
+ cvs_set_dtx.hdr.token = 0;
+ cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
+ cvs_set_dtx.dtx_mode.enable = 0;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_DTX\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ break;
+ }
+ case VSS_MEDIA_ID_AMR_WB_MODEM: {
+ struct cvs_set_amrwb_enc_rate_cmd cvs_set_amrwb_rate;
+ struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
+
+ pr_debug("Setting AMR WB rate\n");
+
+ cvs_set_amrwb_rate.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_set_amrwb_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_set_amrwb_rate) -
+ APR_HDR_SIZE);
+ cvs_set_amrwb_rate.hdr.src_port = 0;
+ cvs_set_amrwb_rate.hdr.dest_port = cvs_handle;
+ cvs_set_amrwb_rate.hdr.token = 0;
+ cvs_set_amrwb_rate.hdr.opcode =
+ VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE;
+ cvs_set_amrwb_rate.amrwb_rate.mode = v->mvs_info.rate;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amrwb_rate);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_AMRWB_RATE\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ /* Disable DTX */
+ pr_debug("Disabling DTX\n");
+
+ cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_set_dtx) - APR_HDR_SIZE);
+ cvs_set_dtx.hdr.src_port = 0;
+ cvs_set_dtx.hdr.dest_port = cvs_handle;
+ cvs_set_dtx.hdr.token = 0;
+ cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
+ cvs_set_dtx.dtx_mode.enable = 0;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_DTX\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ break;
+ }
+ case VSS_MEDIA_ID_G729:
+ case VSS_MEDIA_ID_G711_ALAW:
+ case VSS_MEDIA_ID_G711_MULAW: {
+ struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx;
+ /* Disable DTX */
+ pr_debug("Disabling DTX\n");
+
+ cvs_set_dtx.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_set_dtx.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_set_dtx) - APR_HDR_SIZE);
+ cvs_set_dtx.hdr.src_port = 0;
+ cvs_set_dtx.hdr.dest_port = cvs_handle;
+ cvs_set_dtx.hdr.token = 0;
+ cvs_set_dtx.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE;
+ cvs_set_dtx.dtx_mode.enable = 0;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_DTX\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ break;
+ }
+ default:
+ /* Do nothing. */
+ break;
+ }
+ return 0;
+
+fail:
+ return -EINVAL;
+}
+
+static int voice_send_start_voice_cmd(struct voice_data *v)
+{
+ struct apr_hdr mvm_start_voice_cmd;
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = v->apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ mvm_start_voice_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_start_voice_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_start_voice_cmd) - APR_HDR_SIZE);
+ pr_debug("send mvm_start_voice_cmd pkt size = %d\n",
+ mvm_start_voice_cmd.pkt_size);
+ mvm_start_voice_cmd.src_port = 0;
+ mvm_start_voice_cmd.dest_port = mvm_handle;
+ mvm_start_voice_cmd.token = 0;
+ mvm_start_voice_cmd.opcode = VSS_IMVM_CMD_START_VOICE;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_start_voice_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VSS_IMVM_CMD_START_VOICE\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+ return 0;
+fail:
+ return -EINVAL;
+}
+
+static int voice_send_disable_vocproc_cmd(struct voice_data *v)
+{
+ struct apr_hdr cvp_disable_cmd;
+ int ret = 0;
+ void *apr_cvp;
+ u16 cvp_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvp = v->apr_q6_cvp;
+
+ if (!apr_cvp) {
+ pr_err("%s: apr regist failed\n", __func__);
+ return -EINVAL;
+ }
+ cvp_handle = voice_get_cvp_handle(v);
+
+ /* disable vocproc and wait for respose */
+ cvp_disable_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_disable_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_disable_cmd) - APR_HDR_SIZE);
+ pr_debug("cvp_disable_cmd pkt size = %d, cvp_handle=%d\n",
+ cvp_disable_cmd.pkt_size, cvp_handle);
+ cvp_disable_cmd.src_port = 0;
+ cvp_disable_cmd.dest_port = cvp_handle;
+ cvp_disable_cmd.token = 0;
+ cvp_disable_cmd.opcode = VSS_IVOCPROC_CMD_DISABLE;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_disable_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VSS_IVOCPROC_CMD_DISABLE\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return -EINVAL;
+}
+
+static int voice_send_set_device_cmd(struct voice_data *v)
+{
+ struct cvp_set_device_cmd cvp_setdev_cmd;
+ int ret = 0;
+ void *apr_cvp;
+ u16 cvp_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvp = v->apr_q6_cvp;
+
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ cvp_handle = voice_get_cvp_handle(v);
+
+ /* set device and wait for response */
+ cvp_setdev_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_setdev_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_setdev_cmd) - APR_HDR_SIZE);
+ pr_debug(" send create cvp setdev, pkt size = %d\n",
+ cvp_setdev_cmd.hdr.pkt_size);
+ cvp_setdev_cmd.hdr.src_port = 0;
+ cvp_setdev_cmd.hdr.dest_port = cvp_handle;
+ cvp_setdev_cmd.hdr.token = 0;
+ cvp_setdev_cmd.hdr.opcode = VSS_IVOCPROC_CMD_SET_DEVICE;
+
+ /* Use default topology if invalid value in ACDB */
+ cvp_setdev_cmd.cvp_set_device.tx_topology_id =
+ get_voice_tx_topology();
+ if (cvp_setdev_cmd.cvp_set_device.tx_topology_id == 0)
+ cvp_setdev_cmd.cvp_set_device.tx_topology_id =
+ VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS;
+
+ cvp_setdev_cmd.cvp_set_device.rx_topology_id =
+ get_voice_rx_topology();
+ if (cvp_setdev_cmd.cvp_set_device.rx_topology_id == 0)
+ cvp_setdev_cmd.cvp_set_device.rx_topology_id =
+ VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
+ cvp_setdev_cmd.cvp_set_device.tx_port_id = v->dev_tx.port_id;
+ cvp_setdev_cmd.cvp_set_device.rx_port_id = v->dev_rx.port_id;
+ pr_debug("topology=%d , tx_port_id=%d, rx_port_id=%d\n",
+ cvp_setdev_cmd.cvp_set_device.tx_topology_id,
+ cvp_setdev_cmd.cvp_set_device.tx_port_id,
+ cvp_setdev_cmd.cvp_set_device.rx_port_id);
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_setdev_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VOCPROC_FULL_CONTROL_SESSION\n");
+ goto fail;
+ }
+ pr_debug("wait for cvp create session event\n");
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return -EINVAL;
+}
+
+static int voice_send_stop_voice_cmd(struct voice_data *v)
+{
+ struct apr_hdr mvm_stop_voice_cmd;
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = v->apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ mvm_stop_voice_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_stop_voice_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_stop_voice_cmd) - APR_HDR_SIZE);
+ pr_debug("send mvm_stop_voice_cmd pkt size = %d\n",
+ mvm_stop_voice_cmd.pkt_size);
+ mvm_stop_voice_cmd.src_port = 0;
+ mvm_stop_voice_cmd.dest_port = mvm_handle;
+ mvm_stop_voice_cmd.token = 0;
+ mvm_stop_voice_cmd.opcode = VSS_IMVM_CMD_STOP_VOICE;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_stop_voice_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VSS_IMVM_CMD_STOP_VOICE\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return -EINVAL;
+}
+
+static int voice_setup_vocproc(struct voice_data *v)
+{
+ struct cvp_create_full_ctl_session_cmd cvp_session_cmd;
+ int ret = 0;
+ void *apr_cvp;
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvp = v->apr_q6_cvp;
+
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ /* create cvp session and wait for response */
+ cvp_session_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_session_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_session_cmd) - APR_HDR_SIZE);
+ pr_debug(" send create cvp session, pkt size = %d\n",
+ cvp_session_cmd.hdr.pkt_size);
+ cvp_session_cmd.hdr.src_port = 0;
+ cvp_session_cmd.hdr.dest_port = 0;
+ cvp_session_cmd.hdr.token = 0;
+ cvp_session_cmd.hdr.opcode =
+ VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION;
+
+ /* Use default topology if invalid value in ACDB */
+ cvp_session_cmd.cvp_session.tx_topology_id =
+ get_voice_tx_topology();
+ if (cvp_session_cmd.cvp_session.tx_topology_id == 0)
+ cvp_session_cmd.cvp_session.tx_topology_id =
+ VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS;
+
+ cvp_session_cmd.cvp_session.rx_topology_id =
+ get_voice_rx_topology();
+ if (cvp_session_cmd.cvp_session.rx_topology_id == 0)
+ cvp_session_cmd.cvp_session.rx_topology_id =
+ VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
+
+ cvp_session_cmd.cvp_session.direction = 2; /*tx and rx*/
+ cvp_session_cmd.cvp_session.network_id = VSS_NETWORK_ID_DEFAULT;
+ cvp_session_cmd.cvp_session.tx_port_id = v->dev_tx.port_id;
+ cvp_session_cmd.cvp_session.rx_port_id = v->dev_rx.port_id;
+
+ pr_debug("topology=%d net_id=%d, dir=%d tx_port_id=%d, rx_port_id=%d\n",
+ cvp_session_cmd.cvp_session.tx_topology_id,
+ cvp_session_cmd.cvp_session.network_id,
+ cvp_session_cmd.cvp_session.direction,
+ cvp_session_cmd.cvp_session.tx_port_id,
+ cvp_session_cmd.cvp_session.rx_port_id);
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_session_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VOCPROC_FULL_CONTROL_SESSION\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+
+ /* enable vocproc */
+ ret = voice_send_enable_vocproc_cmd(v);
+ if (ret < 0)
+ goto fail;
+
+ /* attach vocproc */
+ ret = voice_send_attach_vocproc_cmd(v);
+ if (ret < 0)
+ goto fail;
+
+ /* send tty mode if tty device is used */
+ voice_send_tty_mode_cmd(v);
+
+ if (v->voc_path == VOC_PATH_FULL)
+ voice_send_netid_timing_cmd(v);
+
+ return 0;
+
+fail:
+ return -EINVAL;
+}
+
+static int voice_send_enable_vocproc_cmd(struct voice_data *v)
+{
+ int ret = 0;
+ struct apr_hdr cvp_enable_cmd;
+ void *apr_cvp;
+ u16 cvp_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvp = v->apr_q6_cvp;
+
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ cvp_handle = voice_get_cvp_handle(v);
+
+ /* enable vocproc and wait for respose */
+ cvp_enable_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_enable_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_enable_cmd) - APR_HDR_SIZE);
+ pr_debug("cvp_enable_cmd pkt size = %d, cvp_handle=%d\n",
+ cvp_enable_cmd.pkt_size, cvp_handle);
+ cvp_enable_cmd.src_port = 0;
+ cvp_enable_cmd.dest_port = cvp_handle;
+ cvp_enable_cmd.token = 0;
+ cvp_enable_cmd.opcode = VSS_IVOCPROC_CMD_ENABLE;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_enable_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VSS_IVOCPROC_CMD_ENABLE\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return -EINVAL;
+}
+
+static int voice_send_netid_timing_cmd(struct voice_data *v)
+{
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+ struct mvm_set_network_cmd mvm_set_network;
+ struct mvm_set_voice_timing_cmd mvm_set_voice_timing;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = v->apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ ret = voice_config_cvs_vocoder(v);
+ if (ret < 0) {
+ pr_err("%s: Error %d configuring CVS voc",
+ __func__, ret);
+ goto fail;
+ }
+ /* Set network ID. */
+ pr_debug("Setting network ID\n");
+
+ mvm_set_network.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_set_network.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_set_network) - APR_HDR_SIZE);
+ mvm_set_network.hdr.src_port = 0;
+ mvm_set_network.hdr.dest_port = mvm_handle;
+ mvm_set_network.hdr.token = 0;
+ mvm_set_network.hdr.opcode = VSS_ICOMMON_CMD_SET_NETWORK;
+ mvm_set_network.network.network_id = v->mvs_info.network_type;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_network);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_NETWORK\n", __func__, ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+
+ /* Set voice timing. */
+ pr_debug("Setting voice timing\n");
+
+ mvm_set_voice_timing.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_set_voice_timing.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_set_voice_timing) -
+ APR_HDR_SIZE);
+ mvm_set_voice_timing.hdr.src_port = 0;
+ mvm_set_voice_timing.hdr.dest_port = mvm_handle;
+ mvm_set_voice_timing.hdr.token = 0;
+ mvm_set_voice_timing.hdr.opcode = VSS_ICOMMON_CMD_SET_VOICE_TIMING;
+ mvm_set_voice_timing.timing.mode = 0;
+ mvm_set_voice_timing.timing.enc_offset = 8000;
+ mvm_set_voice_timing.timing.dec_req_offset = 3300;
+ mvm_set_voice_timing.timing.dec_offset = 8300;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_voice_timing);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_TIMING\n", __func__, ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return -EINVAL;
+}
+
+static int voice_send_attach_vocproc_cmd(struct voice_data *v)
+{
+ int ret = 0;
+ struct mvm_attach_vocproc_cmd mvm_a_vocproc_cmd;
+ void *apr_mvm;
+ u16 mvm_handle, cvp_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = v->apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+ cvp_handle = voice_get_cvp_handle(v);
+
+ /* attach vocproc and wait for response */
+ mvm_a_vocproc_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_a_vocproc_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_a_vocproc_cmd) - APR_HDR_SIZE);
+ pr_debug("send mvm_a_vocproc_cmd pkt size = %d\n",
+ mvm_a_vocproc_cmd.hdr.pkt_size);
+ mvm_a_vocproc_cmd.hdr.src_port = 0;
+ mvm_a_vocproc_cmd.hdr.dest_port = mvm_handle;
+ mvm_a_vocproc_cmd.hdr.token = 0;
+ mvm_a_vocproc_cmd.hdr.opcode = VSS_ISTREAM_CMD_ATTACH_VOCPROC;
+ mvm_a_vocproc_cmd.mvm_attach_cvp_handle.handle = cvp_handle;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_a_vocproc_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VSS_ISTREAM_CMD_ATTACH_VOCPROC\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return -EINVAL;
+}
+
+static int voice_destroy_vocproc(struct voice_data *v)
+{
+ struct mvm_detach_vocproc_cmd mvm_d_vocproc_cmd;
+ struct apr_hdr cvp_destroy_session_cmd;
+ int ret = 0;
+ void *apr_mvm, *apr_cvp;
+ u16 mvm_handle, cvp_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = v->apr_q6_mvm;
+ apr_cvp = v->apr_q6_cvp;
+
+ if (!apr_mvm || !apr_cvp) {
+ pr_err("%s: apr_mvm or apr_cvp is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+ cvp_handle = voice_get_cvp_handle(v);
+
+ /* send stop voice cmd */
+ voice_send_stop_voice_cmd(v);
+
+ /* detach VOCPROC and wait for response from mvm */
+ mvm_d_vocproc_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_d_vocproc_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_d_vocproc_cmd) - APR_HDR_SIZE);
+ pr_debug("mvm_d_vocproc_cmd pkt size = %d\n",
+ mvm_d_vocproc_cmd.hdr.pkt_size);
+ mvm_d_vocproc_cmd.hdr.src_port = 0;
+ mvm_d_vocproc_cmd.hdr.dest_port = mvm_handle;
+ mvm_d_vocproc_cmd.hdr.token = 0;
+ mvm_d_vocproc_cmd.hdr.opcode = VSS_ISTREAM_CMD_DETACH_VOCPROC;
+ mvm_d_vocproc_cmd.mvm_detach_cvp_handle.handle = cvp_handle;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_d_vocproc_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending VSS_ISTREAM_CMD_DETACH_VOCPROC\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+
+ /* destrop cvp session */
+ cvp_destroy_session_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_destroy_session_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_destroy_session_cmd) - APR_HDR_SIZE);
+ pr_debug("cvp_destroy_session_cmd pkt size = %d\n",
+ cvp_destroy_session_cmd.pkt_size);
+ cvp_destroy_session_cmd.src_port = 0;
+ cvp_destroy_session_cmd.dest_port = cvp_handle;
+ cvp_destroy_session_cmd.token = 0;
+ cvp_destroy_session_cmd.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
+
+ v->cvp_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_destroy_session_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending APRV2_IBASIC_CMD_DESTROY_SESSION\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
+ }
+
+ cvp_handle = 0;
+ voice_set_cvp_handle(v, cvp_handle);
+
+ return 0;
+
+fail:
+ return -EINVAL;
+}
+
+static int voice_send_mute_cmd(struct voice_data *v)
+{
+ struct cvs_set_mute_cmd cvs_mute_cmd;
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = v->apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ cvs_handle = voice_get_cvs_handle(v);
+
+ /* send mute/unmute to cvs */
+ cvs_mute_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_mute_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_mute_cmd) - APR_HDR_SIZE);
+ cvs_mute_cmd.hdr.src_port = 0;
+ cvs_mute_cmd.hdr.dest_port = cvs_handle;
+ cvs_mute_cmd.hdr.token = 0;
+ cvs_mute_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_MUTE;
+ cvs_mute_cmd.cvs_set_mute.direction = 0; /*tx*/
+ cvs_mute_cmd.cvs_set_mute.mute_flag = v->dev_tx.mute;
+
+ pr_info(" mute value =%d\n", cvs_mute_cmd.cvs_set_mute.mute_flag);
+ v->cvs_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_mute_cmd);
+ if (ret < 0) {
+ pr_err("Fail: send STREAM SET MUTE\n");
+ goto fail;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret)
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ return 0;
+fail:
+ return -EINVAL;
+}
+
+static int voice_send_vol_index_cmd(struct voice_data *v)
+{
+ struct cvp_set_rx_volume_index_cmd cvp_vol_cmd;
+ int ret = 0;
+ void *apr_cvp;
+ u16 cvp_handle;
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvp = v->apr_q6_cvp;
+
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ cvp_handle = voice_get_cvp_handle(v);
+
+ /* send volume index to cvp */
+ cvp_vol_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_vol_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_vol_cmd) - APR_HDR_SIZE);
+ cvp_vol_cmd.hdr.src_port = 0;
+ cvp_vol_cmd.hdr.dest_port = cvp_handle;
+ cvp_vol_cmd.hdr.token = 0;
+ cvp_vol_cmd.hdr.opcode = VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX;
+ cvp_vol_cmd.cvp_set_vol_idx.vol_index = v->dev_rx.volume;
+ v->cvp_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_vol_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending RX VOL INDEX\n");
+ return -EINVAL;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int voc_disable_cvp(void)
+{
+ struct voice_data *v = &voice;
+ int ret = 0;
+
+ mutex_lock(&v->lock);
+
+ if (v->voc_state == VOC_RUN) {
+ afe_sidetone(v->dev_tx.port_id, v->dev_rx.port_id, 0, 0);
+ /* send cmd to dsp to disable vocproc */
+ ret = voice_send_disable_vocproc_cmd(v);
+ if (ret < 0) {
+ pr_err("%s: disable vocproc failed\n", __func__);
+ goto fail;
+ }
+ v->voc_state = VOC_CHANGE;
+ }
+
+fail: mutex_unlock(&v->lock);
+
+ return ret;
+}
+
+int voc_enable_cvp(void)
+{
+ struct voice_data *v = &voice;
+ int ret = 0;
+
+ mutex_lock(&v->lock);
+
+ if (v->voc_state == VOC_CHANGE) {
+ ret = voice_send_set_device_cmd(v);
+ if (ret < 0) {
+ pr_err("%s: set device failed\n", __func__);
+ goto fail;
+ }
+ ret = voice_send_enable_vocproc_cmd(v);
+ if (ret < 0) {
+ pr_err("enable vocproc failed\n");
+ goto fail;
+ }
+ ret = afe_sidetone(v->dev_tx.port_id, v->dev_rx.port_id,
+ 1, v->sidetone_gain);
+
+ if (ret < 0)
+ pr_err("AFE command sidetone failed\n");
+
+ v->voc_state = VOC_RUN;
+ }
+
+fail:
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
+int voc_set_tx_mute(uint32_t dir, uint32_t mute)
+{
+ struct voice_data *v = &voice;
+ int ret = 0;
+
+ mutex_lock(&v->lock);
+
+ v->dev_tx.mute = mute;
+
+ if (v->voc_state == VOC_RUN)
+ ret = voice_send_mute_cmd(v);
+
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
+int voc_set_rx_vol_index(uint32_t dir, uint32_t vol_idx)
+{
+ struct voice_data *v = &voice;
+ int ret = 0;
+
+ mutex_lock(&v->lock);
+
+ v->dev_rx.volume = vol_idx;
+
+ if (v->voc_state == VOC_RUN)
+ ret = voice_send_vol_index_cmd(v);
+
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
+void voc_set_rxtx_port(uint32_t port_id, uint32_t dev_type)
+{
+ struct voice_data *v = &voice;
+
+ pr_debug(" port_id=%d, type=%d\n", port_id, dev_type);
+
+ mutex_lock(&v->lock);
+
+ if (dev_type == DEV_RX)
+ v->dev_rx.port_id = port_id;
+ else
+ v->dev_tx.port_id = port_id;
+
+ mutex_unlock(&v->lock);
+
+ return;
+}
+
+void voc_set_route_flag(uint8_t path_dir, uint8_t set)
+{
+ struct voice_data *v = &voice;
+
+ pr_debug("path_dir=%d, set=%d\n", path_dir, set);
+
+ mutex_lock(&v->lock);
+
+ if (path_dir == RX_PATH)
+ v->voc_route_state.rx_route_flag = set;
+ else
+ v->voc_route_state.tx_route_flag = set;
+
+ mutex_unlock(&v->lock);
+
+ return;
+}
+
+uint8_t voc_get_route_flag(uint8_t path_dir)
+{
+ struct voice_data *v = &voice;
+ int ret = 0;
+
+ mutex_lock(&v->lock);
+
+ if (path_dir == RX_PATH)
+ ret = v->voc_route_state.rx_route_flag;
+ else
+ ret = v->voc_route_state.tx_route_flag;
+
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
+int voc_end_voice_call(void)
+{
+ struct voice_data *v = &voice;
+ int ret = 0;
+
+ mutex_lock(&v->lock);
+
+ if (v->voc_state == VOC_RUN) {
+ ret = voice_destroy_vocproc(v);
+ if (ret < 0)
+ pr_err("%s: destroy voice failed\n", __func__);
+ voice_destroy_mvm_cvs_session(v);
+
+ v->voc_state = VOC_RELEASE;
+ }
+ mutex_unlock(&v->lock);
+ return ret;
+}
+
+int voc_start_voice_call(void)
+{
+ struct voice_data *v = &voice;
+ int ret = 0;
+
+ mutex_lock(&v->lock);
+
+ if ((v->voc_state == VOC_INIT) ||
+ (v->voc_state == VOC_RELEASE)) {
+ ret = voice_apr_register(v);
+ if (ret < 0) {
+ pr_err("%s: apr register failed\n", __func__);
+ goto fail;
+ }
+ ret = voice_create_mvm_cvs_session(v);
+ if (ret < 0) {
+ pr_err("create mvm and cvs failed\n");
+ goto fail;
+ }
+ ret = voice_setup_vocproc(v);
+ if (ret < 0) {
+ pr_err("setup voice failed\n");
+ goto fail;
+ }
+ ret = voice_send_start_voice_cmd(v);
+ if (ret < 0) {
+ pr_err("start voice failed\n");
+ goto fail;
+ }
+ ret = afe_sidetone(v->dev_tx.port_id,
+ v->dev_rx.port_id, 1, v->sidetone_gain);
+ if (ret < 0)
+ pr_err("AFE command sidetone failed\n");
+
+ v->voc_state = VOC_RUN;
+ }
+
+fail: mutex_unlock(&v->lock);
+ return ret;
+}
+
+int voc_set_voc_path_full(uint32_t set)
+{
+ int rc = 0;
+
+ pr_debug("set voc path: %d\n", set);
+
+ mutex_lock(&voice.lock);
+
+ if (voice.voc_state == VOC_INIT || voice.voc_state == VOC_RELEASE) {
+ if (set)
+ voice.voc_path = VOC_PATH_FULL;
+ else
+ voice.voc_path = VOC_PATH_PASSIVE;
+ } else {
+ pr_err("%s: Invalid voc path set to %d, in state %d\n",
+ __func__, set, voice.voc_state);
+ rc = -EPERM;
+ }
+
+ mutex_unlock(&voice.lock);
+
+ return rc;
+}
+EXPORT_SYMBOL(voc_set_voc_path_full);
+
+void voc_register_mvs_cb(ul_cb_fn ul_cb,
+ dl_cb_fn dl_cb,
+ void *private_data)
+{
+ voice.mvs_info.ul_cb = ul_cb;
+ voice.mvs_info.dl_cb = dl_cb;
+ voice.mvs_info.private_data = private_data;
+}
+
+void voc_config_vocoder(uint32_t media_type,
+ uint32_t rate,
+ uint32_t network_type)
+{
+ voice.mvs_info.media_type = media_type;
+ voice.mvs_info.rate = rate;
+ voice.mvs_info.network_type = network_type;
+}
+
+static int32_t qdsp_mvm_callback(struct apr_client_data *data, void *priv)
+{
+ uint32_t *ptr;
+ struct voice_data *v;
+
+ if ((data == NULL) || (priv == NULL)) {
+ pr_err("%s: data or priv is NULL\n", __func__);
+ return -EINVAL;
+ }
+ v = priv;
+
+ pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+ data->payload_size, data->opcode);
+
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ if (data->payload_size) {
+ ptr = data->payload;
+
+ pr_info("%x %x\n", ptr[0], ptr[1]);
+ /* ping mvm service ACK */
+ switch (ptr[0]) {
+ case VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION:
+ case VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION:
+ /* Passive session is used for CS call
+ * Full session is used for VoIP call. */
+ pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+ if (!ptr[1]) {
+ pr_debug("%s: MVM handle is %d\n",
+ __func__, data->src_port);
+ voice_set_mvm_handle(v, data->src_port);
+ } else
+ pr_err("got NACK for sending \
+ MVM create session \n");
+ v->mvm_state = CMD_STATUS_SUCCESS;
+ wake_up(&v->mvm_wait);
+ break;
+ case VSS_IMVM_CMD_START_VOICE:
+ case VSS_ISTREAM_CMD_ATTACH_VOCPROC:
+ case VSS_IMVM_CMD_STOP_VOICE:
+ case VSS_ISTREAM_CMD_DETACH_VOCPROC:
+ case VSS_ISTREAM_CMD_SET_TTY_MODE:
+ case APRV2_IBASIC_CMD_DESTROY_SESSION:
+ case VSS_IMVM_CMD_ATTACH_STREAM:
+ case VSS_IMVM_CMD_DETACH_STREAM:
+ case VSS_ICOMMON_CMD_SET_NETWORK:
+ case VSS_ICOMMON_CMD_SET_VOICE_TIMING:
+ pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+ v->mvm_state = CMD_STATUS_SUCCESS;
+ wake_up(&v->mvm_wait);
+ break;
+ default:
+ pr_debug("%s: not match cmd = 0x%x\n",
+ __func__, ptr[0]);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv)
+{
+ uint32_t *ptr;
+ struct voice_data *v;
+
+ if ((data == NULL) || (priv == NULL)) {
+ pr_err("%s: data or priv is NULL\n", __func__);
+ return -EINVAL;
+ }
+ v = priv;
+
+ pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+ data->payload_size, data->opcode);
+
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ if (data->payload_size) {
+ ptr = data->payload;
+
+ pr_info("%x %x\n", ptr[0], ptr[1]);
+ /*response from CVS */
+ switch (ptr[0]) {
+ case VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION:
+ case VSS_ISTREAM_CMD_CREATE_FULL_CONTROL_SESSION:
+ if (!ptr[1]) {
+ pr_debug("%s: CVS handle is %d\n",
+ __func__, data->src_port);
+ voice_set_cvs_handle(v, data->src_port);
+ } else
+ pr_err("got NACK for sending \
+ CVS create session \n");
+ v->cvs_state = CMD_STATUS_SUCCESS;
+ wake_up(&v->cvs_wait);
+ break;
+ case VSS_ISTREAM_CMD_SET_MUTE:
+ case VSS_ISTREAM_CMD_SET_MEDIA_TYPE:
+ case VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE:
+ case VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE:
+ case VSS_ISTREAM_CMD_SET_ENC_DTX_MODE:
+ case VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE:
+ case APRV2_IBASIC_CMD_DESTROY_SESSION:
+ pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+ v->cvs_state = CMD_STATUS_SUCCESS;
+ wake_up(&v->cvs_wait);
+ break;
+ default:
+ pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+ break;
+ }
+ }
+ } else if (data->opcode == VSS_ISTREAM_EVT_SEND_ENC_BUFFER) {
+ uint32_t *voc_pkt = data->payload;
+ uint32_t pkt_len = data->payload_size;
+
+ if (voc_pkt != NULL && v->mvs_info.ul_cb != NULL) {
+ pr_debug("%s: Media type is 0x%x\n",
+ __func__, voc_pkt[0]);
+
+ /* Remove media ID from payload. */
+ voc_pkt++;
+ pkt_len = pkt_len - 4;
+
+ v->mvs_info.ul_cb((uint8_t *)voc_pkt,
+ pkt_len,
+ v->mvs_info.private_data);
+ } else
+ pr_err("%s: voc_pkt is 0x%x ul_cb is 0x%x\n",
+ __func__, (unsigned int)voc_pkt,
+ (unsigned int) v->mvs_info.ul_cb);
+ } else if (data->opcode == VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER) {
+ struct cvs_send_dec_buf_cmd send_dec_buf;
+ int ret = 0;
+ uint32_t pkt_len = 0;
+
+ if (v->mvs_info.dl_cb != NULL) {
+ send_dec_buf.dec_buf.media_id = v->mvs_info.media_type;
+
+ v->mvs_info.dl_cb(
+ (uint8_t *)&send_dec_buf.dec_buf.packet_data,
+ &pkt_len,
+ v->mvs_info.private_data);
+
+ send_dec_buf.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ send_dec_buf.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(send_dec_buf.dec_buf.media_id) + pkt_len);
+ send_dec_buf.hdr.src_port = 0;
+ send_dec_buf.hdr.dest_port = voice_get_cvs_handle(v);
+ send_dec_buf.hdr.token = 0;
+ send_dec_buf.hdr.opcode =
+ VSS_ISTREAM_EVT_SEND_DEC_BUFFER;
+
+ ret = apr_send_pkt(v->apr_q6_cvs,
+ (uint32_t *) &send_dec_buf);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending DEC_BUF\n",
+ __func__, ret);
+ goto fail;
+ }
+ } else
+ pr_debug("%s: dl_cb is NULL\n", __func__);
+ } else if (data->opcode == VSS_ISTREAM_EVT_SEND_DEC_BUFFER)
+ pr_debug("Send dec buf resp\n");
+
+ else
+ pr_debug("Unknown opcode 0x%x\n", data->opcode);
+
+fail:
+ return 0;
+}
+
+static int32_t qdsp_cvp_callback(struct apr_client_data *data, void *priv)
+{
+ uint32_t *ptr;
+ struct voice_data *v;
+
+ if ((data == NULL) || (priv == NULL)) {
+ pr_err("%s: data or priv is NULL\n", __func__);
+ return -EINVAL;
+ }
+ v = priv;
+
+ pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+ data->payload_size, data->opcode);
+
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ if (data->payload_size) {
+ ptr = data->payload;
+
+ pr_info("%x %x\n", ptr[0], ptr[1]);
+
+ switch (ptr[0]) {
+ case VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION:
+ /*response from CVP */
+ pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+ if (!ptr[1]) {
+ voice_set_cvp_handle(v, data->src_port);
+ pr_debug("cvphdl=%d\n", data->src_port);
+ } else
+ pr_err("got NACK from CVP create \
+ session response\n");
+ v->cvp_state = CMD_STATUS_SUCCESS;
+ wake_up(&v->cvp_wait);
+ break;
+ case VSS_IVOCPROC_CMD_SET_DEVICE:
+ case VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX:
+ case VSS_IVOCPROC_CMD_ENABLE:
+ case VSS_IVOCPROC_CMD_DISABLE:
+ case APRV2_IBASIC_CMD_DESTROY_SESSION:
+ v->cvp_state = CMD_STATUS_SUCCESS;
+ wake_up(&v->cvp_wait);
+ break;
+ default:
+ pr_debug("%s: not match cmd = 0x%x\n",
+ __func__, ptr[0]);
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+
+static int __init voice_init(void)
+{
+ int rc = 0;
+ struct voice_data *v = &voice;
+
+ /* set default value */
+ v->default_mute_val = 1; /* default is mute */
+ v->default_vol_val = 0;
+ v->default_sample_val = 8000;
+ v->sidetone_gain = 0x512;
+
+ /* initialize dev_rx and dev_tx */
+ memset(&v->dev_tx, 0, sizeof(struct device_data));
+ memset(&v->dev_rx, 0, sizeof(struct device_data));
+ v->dev_rx.volume = v->default_vol_val;
+ v->dev_tx.mute = v->default_mute_val;
+
+ v->dev_tx.port_id = 1;
+ v->dev_rx.port_id = 0;
+
+ v->voc_state = VOC_INIT;
+ v->voc_path = VOC_PATH_PASSIVE;
+ init_waitqueue_head(&v->mvm_wait);
+ init_waitqueue_head(&v->cvs_wait);
+ init_waitqueue_head(&v->cvp_wait);
+
+ mutex_init(&v->lock);
+
+ v->mvm_full_handle = 0;
+ v->mvm_passive_handle = 0;
+ v->cvs_full_handle = 0;
+ v->cvs_passive_handle = 0;
+ v->cvp_full_handle = 0;
+ v->cvp_passive_handle = 0;
+
+ v->apr_q6_mvm = NULL;
+ v->apr_q6_cvs = NULL;
+ v->apr_q6_cvp = NULL;
+
+ /* Initialize MVS info. */
+ memset(&v->mvs_info, 0, sizeof(v->mvs_info));
+ v->mvs_info.network_type = VSS_NETWORK_ID_DEFAULT;
+
+ return rc;
+}
+
+device_initcall(voice_init);
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
new file mode 100644
index 0000000..f9e1bc4
--- /dev/null
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -0,0 +1,686 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __QDSP6VOICE_H__
+#define __QDSP6VOICE_H__
+
+#include <mach/qdsp6v2/apr.h>
+
+#define MAX_VOC_PKT_SIZE 322
+
+struct voice_header {
+ uint32_t id;
+ uint32_t data_len;
+};
+
+struct voice_init {
+ struct voice_header hdr;
+ void *cb_handle;
+};
+
+/* Device information payload structure */
+
+struct device_data {
+ uint32_t volume; /* in index */
+ uint32_t mute;
+ uint32_t sample;
+ uint32_t enabled;
+ uint32_t dev_id;
+ uint32_t port_id;
+};
+
+struct voice_dev_route_state {
+ u16 rx_route_flag;
+ u16 tx_route_flag;
+};
+
+enum {
+ VOC_INIT = 0,
+ VOC_RUN,
+ VOC_CHANGE,
+ VOC_RELEASE,
+};
+
+/* TO MVM commands */
+#define VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION 0x000110FF
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION 0x000110FE
+/* Create a new full control MVM session. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION 0x0001003C
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_ATTACH_STREAM 0x0001123C
+/* Attach a stream to the MVM. */
+
+#define VSS_IMVM_CMD_DETACH_STREAM 0x0001123D
+/* Detach a stream from the MVM. */
+
+#define VSS_IMVM_CMD_START_VOICE 0x00011190
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_STOP_VOICE 0x00011192
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_ATTACH_VOCPROC 0x000110F8
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_DETACH_VOCPROC 0x000110F9
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+
+#define VSS_ISTREAM_CMD_SET_TTY_MODE 0x00011196
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ICOMMON_CMD_SET_NETWORK 0x0001119C
+/* Set the network type. */
+
+#define VSS_ICOMMON_CMD_SET_VOICE_TIMING 0x000111E0
+/* Set the voice timing parameters. */
+
+struct vss_istream_cmd_set_tty_mode_t {
+ uint32_t mode;
+ /**<
+ * TTY mode.
+ *
+ * 0 : TTY disabled
+ * 1 : HCO
+ * 2 : VCO
+ * 3 : FULL
+ */
+} __packed;
+
+struct vss_istream_cmd_attach_vocproc_t {
+ uint16_t handle;
+ /**< Handle of vocproc being attached. */
+} __packed;
+
+struct vss_istream_cmd_detach_vocproc_t {
+ uint16_t handle;
+ /**< Handle of vocproc being detached. */
+} __packed;
+
+struct vss_imvm_cmd_attach_stream_t {
+ uint16_t handle;
+ /* The stream handle to attach. */
+} __packed;
+
+struct vss_imvm_cmd_detach_stream_t {
+ uint16_t handle;
+ /* The stream handle to detach. */
+} __packed;
+
+struct vss_icommon_cmd_set_network_t {
+ uint32_t network_id;
+ /* Network ID. (Refer to VSS_NETWORK_ID_XXX). */
+} __packed;
+
+struct vss_icommon_cmd_set_voice_timing_t {
+ uint16_t mode;
+ /*
+ * The vocoder frame synchronization mode.
+ *
+ * 0 : No frame sync.
+ * 1 : Hard VFR (20ms Vocoder Frame Reference interrupt).
+ */
+ uint16_t enc_offset;
+ /*
+ * The offset in microseconds from the VFR to deliver a Tx vocoder
+ * packet. The offset should be less than 20000us.
+ */
+ uint16_t dec_req_offset;
+ /*
+ * The offset in microseconds from the VFR to request for an Rx vocoder
+ * packet. The offset should be less than 20000us.
+ */
+ uint16_t dec_offset;
+ /*
+ * The offset in microseconds from the VFR to indicate the deadline to
+ * receive an Rx vocoder packet. The offset should be less than 20000us.
+ * Rx vocoder packets received after this deadline are not guaranteed to
+ * be processed.
+ */
+} __packed;
+
+struct vss_imvm_cmd_create_full_control_session_t {
+ char name[20];
+ /*
+ * A variable-sized stream name.
+ *
+ * The stream name size is the payload size minus the size of the other
+ * fields.
+ */
+} __packed;
+
+
+struct mvm_attach_vocproc_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_attach_vocproc_t mvm_attach_cvp_handle;
+} __packed;
+
+struct mvm_detach_vocproc_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_detach_vocproc_t mvm_detach_cvp_handle;
+} __packed;
+
+struct mvm_create_passive_ctl_session_cmd {
+ struct apr_hdr hdr;
+} __packed;
+
+struct mvm_create_full_ctl_session_cmd {
+ struct apr_hdr hdr;
+ struct vss_imvm_cmd_create_full_control_session_t mvm_session;
+} __packed;
+
+struct mvm_set_tty_mode_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_set_tty_mode_t tty_mode;
+} __packed;
+
+struct mvm_attach_stream_cmd {
+ struct apr_hdr hdr;
+ struct vss_imvm_cmd_attach_stream_t attach_stream;
+} __packed;
+
+struct mvm_detach_stream_cmd {
+ struct apr_hdr hdr;
+ struct vss_imvm_cmd_detach_stream_t detach_stream;
+} __packed;
+
+struct mvm_set_network_cmd {
+ struct apr_hdr hdr;
+ struct vss_icommon_cmd_set_network_t network;
+} __packed;
+
+struct mvm_set_voice_timing_cmd {
+ struct apr_hdr hdr;
+ struct vss_icommon_cmd_set_voice_timing_t timing;
+} __packed;
+
+/* TO CVS commands */
+#define VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION 0x00011140
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_CREATE_FULL_CONTROL_SESSION 0x000110F7
+/* Create a new full control stream session. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION 0x0001003C
+
+#define VSS_ISTREAM_CMD_SET_MUTE 0x00011022
+
+#define VSS_ISTREAM_CMD_SET_MEDIA_TYPE 0x00011186
+/* Set media type on the stream. */
+
+#define VSS_ISTREAM_EVT_SEND_ENC_BUFFER 0x00011015
+/* Event sent by the stream to its client to provide an encoded packet. */
+
+#define VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER 0x00011017
+/* Event sent by the stream to its client requesting for a decoder packet.
+ * The client should respond with a VSS_ISTREAM_EVT_SEND_DEC_BUFFER event.
+ */
+
+#define VSS_ISTREAM_EVT_SEND_DEC_BUFFER 0x00011016
+/* Event sent by the client to the stream in response to a
+ * VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER event, providing a decoder packet.
+ */
+
+#define VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE 0x0001113E
+/* Set AMR encoder rate. */
+
+#define VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE 0x0001113F
+/* Set AMR-WB encoder rate. */
+
+#define VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE 0x00011019
+/* Set encoder minimum and maximum rate. */
+
+#define VSS_ISTREAM_CMD_SET_ENC_DTX_MODE 0x0001101D
+/* Set encoder DTX mode. */
+
+struct vss_istream_cmd_create_passive_control_session_t {
+ char name[20];
+ /**<
+ * A variable-sized stream name.
+ *
+ * The stream name size is the payload size minus the size of the other
+ * fields.
+ */
+} __packed;
+
+struct vss_istream_cmd_set_mute_t {
+ uint16_t direction;
+ /**<
+ * 0 : TX only
+ * 1 : RX only
+ * 2 : TX and Rx
+ */
+ uint16_t mute_flag;
+ /**<
+ * Mute, un-mute.
+ *
+ * 0 : Silence disable
+ * 1 : Silence enable
+ * 2 : CNG enable. Applicable to TX only. If set on RX behavior
+ * will be the same as 1
+ */
+} __packed;
+
+struct vss_istream_cmd_create_full_control_session_t {
+ uint16_t direction;
+ /*
+ * Stream direction.
+ *
+ * 0 : TX only
+ * 1 : RX only
+ * 2 : TX and RX
+ * 3 : TX and RX loopback
+ */
+ uint32_t enc_media_type;
+ /* Tx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+ uint32_t dec_media_type;
+ /* Rx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+ uint32_t network_id;
+ /* Network ID. (Refer to VSS_NETWORK_ID_XXX). */
+ char name[20];
+ /*
+ * A variable-sized stream name.
+ *
+ * The stream name size is the payload size minus the size of the other
+ * fields.
+ */
+} __packed;
+
+struct vss_istream_cmd_set_media_type_t {
+ uint32_t rx_media_id;
+ /* Set the Rx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+ uint32_t tx_media_id;
+ /* Set the Tx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+} __packed;
+
+struct vss_istream_evt_send_enc_buffer_t {
+ uint32_t media_id;
+ /* Media ID of the packet. */
+ uint8_t packet_data[MAX_VOC_PKT_SIZE];
+ /* Packet data buffer. */
+} __packed;
+
+struct vss_istream_evt_send_dec_buffer_t {
+ uint32_t media_id;
+ /* Media ID of the packet. */
+ uint8_t packet_data[MAX_VOC_PKT_SIZE];
+ /* Packet data. */
+} __packed;
+
+struct vss_istream_cmd_voc_amr_set_enc_rate_t {
+ uint32_t mode;
+ /* Set the AMR encoder rate.
+ *
+ * 0x00000000 : 4.75 kbps
+ * 0x00000001 : 5.15 kbps
+ * 0x00000002 : 5.90 kbps
+ * 0x00000003 : 6.70 kbps
+ * 0x00000004 : 7.40 kbps
+ * 0x00000005 : 7.95 kbps
+ * 0x00000006 : 10.2 kbps
+ * 0x00000007 : 12.2 kbps
+ */
+} __packed;
+
+struct vss_istream_cmd_voc_amrwb_set_enc_rate_t {
+ uint32_t mode;
+ /* Set the AMR-WB encoder rate.
+ *
+ * 0x00000000 : 6.60 kbps
+ * 0x00000001 : 8.85 kbps
+ * 0x00000002 : 12.65 kbps
+ * 0x00000003 : 14.25 kbps
+ * 0x00000004 : 15.85 kbps
+ * 0x00000005 : 18.25 kbps
+ * 0x00000006 : 19.85 kbps
+ * 0x00000007 : 23.05 kbps
+ * 0x00000008 : 23.85 kbps
+ */
+} __packed;
+
+struct vss_istream_cmd_cdma_set_enc_minmax_rate_t {
+ uint16_t min_rate;
+ /* Set the lower bound encoder rate.
+ *
+ * 0x0000 : Blank frame
+ * 0x0001 : Eighth rate
+ * 0x0002 : Quarter rate
+ * 0x0003 : Half rate
+ * 0x0004 : Full rate
+ */
+ uint16_t max_rate;
+ /* Set the upper bound encoder rate.
+ *
+ * 0x0000 : Blank frame
+ * 0x0001 : Eighth rate
+ * 0x0002 : Quarter rate
+ * 0x0003 : Half rate
+ * 0x0004 : Full rate
+ */
+} __packed;
+
+struct vss_istream_cmd_set_enc_dtx_mode_t {
+ uint32_t enable;
+ /* Toggle DTX on or off.
+ *
+ * 0 : Disables DTX
+ * 1 : Enables DTX
+ */
+} __packed;
+
+struct cvs_create_passive_ctl_session_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_create_passive_control_session_t cvs_session;
+} __packed;
+
+struct cvs_create_full_ctl_session_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_create_full_control_session_t cvs_session;
+};
+
+struct cvs_destroy_session_cmd {
+ struct apr_hdr hdr;
+} __packed;
+
+struct cvs_set_mute_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_set_mute_t cvs_set_mute;
+} __packed;
+
+struct cvs_set_media_type_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_set_media_type_t media_type;
+} __packed;
+
+struct cvs_send_dec_buf_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_evt_send_dec_buffer_t dec_buf;
+} __packed;
+
+struct cvs_set_amr_enc_rate_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_voc_amr_set_enc_rate_t amr_rate;
+} __packed;
+
+struct cvs_set_amrwb_enc_rate_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_voc_amrwb_set_enc_rate_t amrwb_rate;
+} __packed;
+
+struct cvs_set_cdma_enc_minmax_rate_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_cdma_set_enc_minmax_rate_t cdma_rate;
+} __packed;
+
+struct cvs_set_enc_dtx_mode_cmd {
+ struct apr_hdr hdr;
+ struct vss_istream_cmd_set_enc_dtx_mode_t dtx_mode;
+} __packed;
+
+/* TO CVP commands */
+
+#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION 0x000100C3
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION 0x0001003C
+
+#define VSS_IVOCPROC_CMD_SET_DEVICE 0x000100C4
+
+#define VSS_IVOCPROC_CMD_SET_VP3_DATA 0x000110EB
+
+#define VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX 0x000110EE
+
+#define VSS_IVOCPROC_CMD_ENABLE 0x000100C6
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IVOCPROC_CMD_DISABLE 0x000110E1
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IVOCPROC_TOPOLOGY_ID_NONE 0x00010F70
+#define VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS 0x00010F71
+#define VSS_IVOCPROC_TOPOLOGY_ID_TX_DM_FLUENCE 0x00010F72
+
+#define VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT 0x00010F77
+
+/* Newtwork IDs */
+#define VSS_NETWORK_ID_DEFAULT 0x00010037
+#define VSS_NETWORK_ID_VOIP_NB 0x00011240
+#define VSS_NETWORK_ID_VOIP_WB 0x00011241
+#define VSS_NETWORK_ID_VOIP_WV 0x00011242
+
+/* Media types */
+#define VSS_MEDIA_ID_EVRC_MODEM 0x00010FC2
+/* 80-VF690-47 CDMA enhanced variable rate vocoder modem format. */
+#define VSS_MEDIA_ID_AMR_NB_MODEM 0x00010FC6
+/* 80-VF690-47 UMTS AMR-NB vocoder modem format. */
+#define VSS_MEDIA_ID_AMR_WB_MODEM 0x00010FC7
+/* 80-VF690-47 UMTS AMR-WB vocoder modem format. */
+#define VSS_MEDIA_ID_PCM_NB 0x00010FCB
+#define VSS_MEDIA_ID_PCM_WB 0x00010FCC
+/* Linear PCM (16-bit, little-endian). */
+#define VSS_MEDIA_ID_G711_ALAW 0x00010FCD
+/* G.711 a-law (contains two 10ms vocoder frames). */
+#define VSS_MEDIA_ID_G711_MULAW 0x00010FCE
+/* G.711 mu-law (contains two 10ms vocoder frames). */
+#define VSS_MEDIA_ID_G729 0x00010FD0
+/* G.729AB (contains two 10ms vocoder frames. */
+
+#define VOICE_CMD_SET_PARAM 0x00011006
+#define VOICE_CMD_GET_PARAM 0x00011007
+#define VOICE_EVT_GET_PARAM_ACK 0x00011008
+
+struct vss_ivocproc_cmd_create_full_control_session_t {
+ uint16_t direction;
+ /*
+ * stream direction.
+ * 0 : TX only
+ * 1 : RX only
+ * 2 : TX and RX
+ */
+ uint32_t tx_port_id;
+ /*
+ * TX device port ID which vocproc will connect to. If not supplying a
+ * port ID set to VSS_IVOCPROC_PORT_ID_NONE.
+ */
+ uint32_t tx_topology_id;
+ /*
+ * Tx leg topology ID. If not supplying a topology ID set to
+ * VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+ */
+ uint32_t rx_port_id;
+ /*
+ * RX device port ID which vocproc will connect to. If not supplying a
+ * port ID set to VSS_IVOCPROC_PORT_ID_NONE.
+ */
+ uint32_t rx_topology_id;
+ /*
+ * Rx leg topology ID. If not supplying a topology ID set to
+ * VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+ */
+ int32_t network_id;
+ /*
+ * Network ID. (Refer to VSS_NETWORK_ID_XXX). If not supplying a network
+ * ID set to VSS_NETWORK_ID_DEFAULT.
+ */
+} __packed;
+
+struct vss_ivocproc_cmd_set_volume_index_t {
+ uint16_t vol_index;
+ /**<
+ * Volume index utilized by the vocproc to index into the volume table
+ * provided in VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE and set
+ * volume on the VDSP.
+ */
+} __packed;
+
+struct vss_ivocproc_cmd_set_device_t {
+ uint32_t tx_port_id;
+ /**<
+ * TX device port ID which vocproc will connect to.
+ * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+ */
+ uint32_t tx_topology_id;
+ /**<
+ * TX leg topology ID.
+ * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+ * pre/post-processing blocks and is pass-through.
+ */
+ int32_t rx_port_id;
+ /**<
+ * RX device port ID which vocproc will connect to.
+ * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+ */
+ uint32_t rx_topology_id;
+ /**<
+ * RX leg topology ID.
+ * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+ * pre/post-processing blocks and is pass-through.
+ */
+} __packed;
+
+struct cvp_create_full_ctl_session_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivocproc_cmd_create_full_control_session_t cvp_session;
+} __packed;
+
+struct cvp_command {
+ struct apr_hdr hdr;
+} __packed;
+
+struct cvp_set_device_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivocproc_cmd_set_device_t cvp_set_device;
+} __packed;
+
+struct cvp_set_vp3_data_cmd {
+ struct apr_hdr hdr;
+} __packed;
+
+struct cvp_set_rx_volume_index_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivocproc_cmd_set_volume_index_t cvp_set_vol_idx;
+} __packed;
+
+/* CB for up-link packets. */
+typedef void (*ul_cb_fn)(uint8_t *voc_pkt,
+ uint32_t pkt_len,
+ void *private_data);
+
+/* CB for down-link packets. */
+typedef void (*dl_cb_fn)(uint8_t *voc_pkt,
+ uint32_t *pkt_len,
+ void *private_data);
+
+
+struct mvs_driver_info {
+ uint32_t media_type;
+ uint32_t rate;
+ uint32_t network_type;
+ ul_cb_fn ul_cb;
+ dl_cb_fn dl_cb;
+ void *private_data;
+};
+
+struct incall_rec_info {
+ uint32_t pending;
+ uint32_t rec_mode;
+};
+
+struct incall_music_info {
+ uint32_t pending;
+ uint32_t playing;
+};
+
+struct voice_data {
+ int voc_state;/*INIT, CHANGE, RELEASE, RUN */
+ uint32_t voc_path;
+
+ wait_queue_head_t mvm_wait;
+ wait_queue_head_t cvs_wait;
+ wait_queue_head_t cvp_wait;
+
+ uint32_t device_events;
+
+ /* cache the values related to Rx and Tx */
+ struct device_data dev_rx;
+ struct device_data dev_tx;
+
+ /* these default values are for all devices */
+ uint32_t default_mute_val;
+ uint32_t default_vol_val;
+ uint32_t default_sample_val;
+
+ /* APR to MVM in the Q6 */
+ void *apr_q6_mvm;
+ /* APR to CVS in the Q6 */
+ void *apr_q6_cvs;
+ /* APR to CVP in the Q6 */
+ void *apr_q6_cvp;
+
+ u32 mvm_state;
+ u32 cvs_state;
+ u32 cvp_state;
+
+ /* Handle to MVM in the Q6 */
+ u16 mvm_passive_handle; /* for cs call */
+ u16 mvm_full_handle; /* for voip */
+ /* Handle to CVS in the Q6 */
+ u16 cvs_passive_handle;
+ u16 cvs_full_handle;
+ /* Handle to CVP in the Q6 */
+ u16 cvp_passive_handle;
+ u16 cvp_full_handle;
+
+ struct mutex lock;
+
+ struct mvs_driver_info mvs_info;
+
+ uint16_t sidetone_gain;
+
+ struct voice_dev_route_state voc_route_state;
+};
+
+int voc_set_voc_path_full(uint32_t set);
+
+void voc_register_mvs_cb(ul_cb_fn ul_cb,
+ dl_cb_fn dl_cb,
+ void *private_data);
+
+void voc_config_vocoder(uint32_t media_type,
+ uint32_t rate,
+ uint32_t network_type);
+
+enum {
+ DEV_RX = 0,
+ DEV_TX,
+};
+
+enum {
+ RX_PATH = 0,
+ TX_PATH,
+};
+
+/* called by alsa driver */
+int voc_start_voice_call(void);
+int voc_end_voice_call(void);
+void voc_set_rxtx_port(uint32_t dev_port_id, uint32_t dev_type);
+int voc_set_rx_vol_index(uint32_t dir, uint32_t voc_idx);
+int voc_set_tx_mute(uint32_t dir, uint32_t mute);
+int voc_disable_cvp(void);
+int voc_enable_cvp(void);
+void voc_set_route_flag(uint8_t path_dir, uint8_t set);
+uint8_t voc_get_route_flag(uint8_t path_dir);
+
+#endif