08bb73698a
Between Linux-4.9 and Linux-4.14, upstream has updated the ION APIs significantly to make ION ready to bring out of staging folder. This has changed the way ION and dma_buf APIs used to work together for allocating, mapping and deallocating ION buffers. Update MSM Audio ION wrapper functions used by audio drivers to reflect these ION API changes as per upstream ION. Change-Id: I63097e147a397aa3a538f69ac88b6fb10871c3dc Signed-off-by: Banajit Goswami <bgoswami@codeaurora.org>
1957 lines
51 KiB
C
1957 lines
51 KiB
C
/* Copyright (c) 2012-2018, The Linux Foundation. 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/fs.h>
|
|
#include <linux/module.h>
|
|
#include <linux/miscdevice.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/msm_audio_calibration.h>
|
|
#include <linux/atomic.h>
|
|
#include <linux/compat.h>
|
|
#include <dsp/msm_audio_ion.h>
|
|
#include <dsp/rtac.h>
|
|
#include <dsp/q6asm-v2.h>
|
|
#include <dsp/q6afe-v2.h>
|
|
#include <dsp/q6adm-v2.h>
|
|
#include <dsp/apr_audio-v2.h>
|
|
#include <dsp/q6voice.h>
|
|
#include "adsp_err.h"
|
|
|
|
|
|
/* Max size of payload (buf size - apr header) */
|
|
#define MAX_PAYLOAD_SIZE 4076
|
|
#define RTAC_MAX_ACTIVE_VOICE_COMBOS 2
|
|
#define RTAC_MAX_ACTIVE_POPP 8
|
|
#define RTAC_BUF_SIZE 163840
|
|
|
|
#define TIMEOUT_MS 1000
|
|
|
|
struct rtac_cal_block_data rtac_cal[MAX_RTAC_BLOCKS] = {
|
|
/* ADM_RTAC_CAL */
|
|
{{RTAC_BUF_SIZE, 0, 0}, {0, 0, 0} },
|
|
/* ASM_RTAC_CAL */
|
|
{{RTAC_BUF_SIZE, 0, 0}, {0, 0, 0} },
|
|
/* VOICE_RTAC_CAL */
|
|
{{RTAC_BUF_SIZE, 0, 0}, {0, 0, 0} },
|
|
/* AFE_RTAC_CAL */
|
|
{{RTAC_BUF_SIZE, 0, 0}, {0, 0, 0} }
|
|
};
|
|
|
|
struct rtac_common_data {
|
|
atomic_t usage_count;
|
|
atomic_t apr_err_code;
|
|
};
|
|
|
|
static struct rtac_common_data rtac_common;
|
|
|
|
/* APR data */
|
|
struct rtac_apr_data {
|
|
void *apr_handle;
|
|
atomic_t cmd_state;
|
|
wait_queue_head_t cmd_wait;
|
|
};
|
|
|
|
static struct rtac_apr_data rtac_adm_apr_data;
|
|
static struct rtac_apr_data rtac_asm_apr_data[ASM_ACTIVE_STREAMS_ALLOWED + 1];
|
|
static struct rtac_apr_data rtac_afe_apr_data;
|
|
static struct rtac_apr_data rtac_voice_apr_data[RTAC_VOICE_MODES];
|
|
|
|
/* ADM info & APR */
|
|
static struct rtac_adm rtac_adm_data;
|
|
static u32 *rtac_adm_buffer;
|
|
|
|
|
|
/* ASM APR */
|
|
static u32 *rtac_asm_buffer;
|
|
|
|
static u32 *rtac_afe_buffer;
|
|
|
|
/* Voice info & APR */
|
|
struct rtac_voice_data_t {
|
|
uint32_t tx_topology_id;
|
|
uint32_t rx_topology_id;
|
|
uint32_t tx_afe_topology;
|
|
uint32_t rx_afe_topology;
|
|
uint32_t tx_afe_port;
|
|
uint32_t rx_afe_port;
|
|
uint16_t cvs_handle;
|
|
uint16_t cvp_handle;
|
|
uint32_t tx_acdb_id;
|
|
uint32_t rx_acdb_id;
|
|
};
|
|
|
|
struct rtac_voice {
|
|
uint32_t num_of_voice_combos;
|
|
struct rtac_voice_data_t voice[RTAC_MAX_ACTIVE_VOICE_COMBOS];
|
|
};
|
|
|
|
struct rtac_afe_user_data {
|
|
uint32_t buf_size;
|
|
uint32_t cmd_size;
|
|
uint32_t port_id;
|
|
union {
|
|
struct rtac_afe_set {
|
|
struct afe_port_cmd_set_param_v2 cmd;
|
|
struct afe_port_param_data_v2 data;
|
|
} rtac_afe_set;
|
|
struct rtac_afe_get {
|
|
struct afe_port_cmd_get_param_v2 cmd;
|
|
struct afe_port_param_data_v2 data;
|
|
} rtac_afe_get;
|
|
};
|
|
} __packed;
|
|
|
|
static struct rtac_voice rtac_voice_data;
|
|
static u32 *rtac_voice_buffer;
|
|
static u32 voice_session_id[RTAC_MAX_ACTIVE_VOICE_COMBOS];
|
|
|
|
|
|
struct mutex rtac_adm_mutex;
|
|
struct mutex rtac_adm_apr_mutex;
|
|
struct mutex rtac_asm_apr_mutex;
|
|
struct mutex rtac_voice_mutex;
|
|
struct mutex rtac_voice_apr_mutex;
|
|
struct mutex rtac_afe_apr_mutex;
|
|
|
|
int rtac_clear_mapping(uint32_t cal_type)
|
|
{
|
|
int result = 0;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
|
|
if (cal_type >= MAX_RTAC_BLOCKS) {
|
|
pr_debug("%s: invalid cal type %d\n", __func__, cal_type);
|
|
result = -EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
rtac_cal[cal_type].map_data.map_handle = 0;
|
|
done:
|
|
return result;
|
|
}
|
|
|
|
int rtac_allocate_cal_buffer(uint32_t cal_type)
|
|
{
|
|
int result = 0;
|
|
size_t len;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
|
|
if (cal_type >= MAX_RTAC_BLOCKS) {
|
|
pr_err("%s: cal_type %d is invalid!\n",
|
|
__func__, cal_type);
|
|
result = -EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
if (rtac_cal[cal_type].cal_data.paddr != 0) {
|
|
pr_err("%s: memory already allocated! cal_type %d, paddr 0x%pK\n",
|
|
__func__, cal_type, &rtac_cal[cal_type].cal_data.paddr);
|
|
result = -EPERM;
|
|
goto done;
|
|
}
|
|
|
|
result = msm_audio_ion_alloc(&rtac_cal[cal_type].map_data.dma_buf,
|
|
rtac_cal[cal_type].map_data.map_size,
|
|
&rtac_cal[cal_type].cal_data.paddr,
|
|
&len,
|
|
&rtac_cal[cal_type].cal_data.kvaddr);
|
|
if (result < 0) {
|
|
pr_err("%s: ION create client for RTAC failed\n",
|
|
__func__);
|
|
goto done;
|
|
}
|
|
|
|
pr_debug("%s: cal_type %d, paddr 0x%pK, kvaddr 0x%pK, map_size 0x%x\n",
|
|
__func__, cal_type,
|
|
&rtac_cal[cal_type].cal_data.paddr,
|
|
rtac_cal[cal_type].cal_data.kvaddr,
|
|
rtac_cal[cal_type].map_data.map_size);
|
|
done:
|
|
return result;
|
|
}
|
|
|
|
int rtac_free_cal_buffer(uint32_t cal_type)
|
|
{
|
|
int result = 0;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
|
|
if (cal_type >= MAX_RTAC_BLOCKS) {
|
|
pr_err("%s: cal_type %d is invalid!\n",
|
|
__func__, cal_type);
|
|
result = -EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
if (rtac_cal[cal_type].map_data.dma_buf == NULL) {
|
|
pr_debug("%s: cal_type %d not allocated!\n",
|
|
__func__, cal_type);
|
|
goto done;
|
|
}
|
|
|
|
result = msm_audio_ion_free(rtac_cal[cal_type].map_data.dma_buf);
|
|
if (result < 0) {
|
|
pr_err("%s: ION free for RTAC failed! cal_type %d, paddr 0x%pK\n",
|
|
__func__, cal_type, &rtac_cal[cal_type].cal_data.paddr);
|
|
goto done;
|
|
}
|
|
|
|
rtac_cal[cal_type].map_data.map_handle = 0;
|
|
rtac_cal[cal_type].map_data.dma_buf = NULL;
|
|
rtac_cal[cal_type].cal_data.size = 0;
|
|
rtac_cal[cal_type].cal_data.kvaddr = 0;
|
|
rtac_cal[cal_type].cal_data.paddr = 0;
|
|
done:
|
|
return result;
|
|
}
|
|
|
|
int rtac_map_cal_buffer(uint32_t cal_type)
|
|
{
|
|
int result = 0;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
|
|
if (cal_type >= MAX_RTAC_BLOCKS) {
|
|
pr_err("%s: cal_type %d is invalid!\n",
|
|
__func__, cal_type);
|
|
result = -EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
if (rtac_cal[cal_type].map_data.map_handle != 0) {
|
|
pr_err("%s: already mapped cal_type %d\n",
|
|
__func__, cal_type);
|
|
result = -EPERM;
|
|
goto done;
|
|
}
|
|
|
|
if (rtac_cal[cal_type].cal_data.paddr == 0) {
|
|
pr_err("%s: physical address is NULL cal_type %d\n",
|
|
__func__, cal_type);
|
|
result = -EPERM;
|
|
goto done;
|
|
}
|
|
|
|
switch (cal_type) {
|
|
case ADM_RTAC_CAL:
|
|
result = adm_map_rtac_block(&rtac_cal[cal_type]);
|
|
break;
|
|
case ASM_RTAC_CAL:
|
|
result = q6asm_map_rtac_block(&rtac_cal[cal_type]);
|
|
break;
|
|
case VOICE_RTAC_CAL:
|
|
result = voc_map_rtac_block(&rtac_cal[cal_type]);
|
|
break;
|
|
case AFE_RTAC_CAL:
|
|
result = afe_map_rtac_block(&rtac_cal[cal_type]);
|
|
break;
|
|
}
|
|
if (result < 0) {
|
|
pr_err("%s: map RTAC failed! cal_type %d\n",
|
|
__func__, cal_type);
|
|
goto done;
|
|
}
|
|
done:
|
|
return result;
|
|
}
|
|
|
|
int rtac_unmap_cal_buffer(uint32_t cal_type)
|
|
{
|
|
int result = 0;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
|
|
if (cal_type >= MAX_RTAC_BLOCKS) {
|
|
pr_err("%s: cal_type %d is invalid!\n",
|
|
__func__, cal_type);
|
|
result = -EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
if (rtac_cal[cal_type].map_data.map_handle == 0) {
|
|
pr_debug("%s: nothing to unmap cal_type %d\n",
|
|
__func__, cal_type);
|
|
goto done;
|
|
}
|
|
|
|
switch (cal_type) {
|
|
case ADM_RTAC_CAL:
|
|
result = adm_unmap_rtac_block(
|
|
&rtac_cal[cal_type].map_data.map_handle);
|
|
break;
|
|
case ASM_RTAC_CAL:
|
|
result = q6asm_unmap_rtac_block(
|
|
&rtac_cal[cal_type].map_data.map_handle);
|
|
break;
|
|
case VOICE_RTAC_CAL:
|
|
result = voc_unmap_rtac_block(
|
|
&rtac_cal[cal_type].map_data.map_handle);
|
|
break;
|
|
case AFE_RTAC_CAL:
|
|
result = afe_unmap_rtac_block(
|
|
&rtac_cal[cal_type].map_data.map_handle);
|
|
break;
|
|
}
|
|
if (result < 0) {
|
|
pr_err("%s: unmap RTAC failed! cal_type %d\n",
|
|
__func__, cal_type);
|
|
goto done;
|
|
}
|
|
done:
|
|
return result;
|
|
}
|
|
|
|
static int rtac_open(struct inode *inode, struct file *f)
|
|
{
|
|
int result = 0;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
|
|
atomic_inc(&rtac_common.usage_count);
|
|
return result;
|
|
}
|
|
|
|
static int rtac_release(struct inode *inode, struct file *f)
|
|
{
|
|
int result = 0;
|
|
int result2 = 0;
|
|
int i;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
|
|
atomic_dec(&rtac_common.usage_count);
|
|
pr_debug("%s: ref count %d!\n", __func__,
|
|
atomic_read(&rtac_common.usage_count));
|
|
|
|
if (atomic_read(&rtac_common.usage_count) > 0)
|
|
goto done;
|
|
|
|
for (i = 0; i < MAX_RTAC_BLOCKS; i++) {
|
|
result2 = rtac_unmap_cal_buffer(i);
|
|
if (result2 < 0) {
|
|
pr_err("%s: unmap buffer failed! error %d!\n",
|
|
__func__, result2);
|
|
result = result2;
|
|
}
|
|
|
|
result2 = rtac_free_cal_buffer(i);
|
|
if (result2 < 0) {
|
|
pr_err("%s: free buffer failed! error %d!\n",
|
|
__func__, result2);
|
|
result = result2;
|
|
}
|
|
}
|
|
done:
|
|
return result;
|
|
}
|
|
|
|
|
|
/* ADM Info */
|
|
void add_popp(u32 dev_idx, u32 port_id, u32 popp_id)
|
|
{
|
|
u32 i = 0;
|
|
|
|
for (; i < rtac_adm_data.device[dev_idx].num_of_popp; i++)
|
|
if (rtac_adm_data.device[dev_idx].popp[i].popp == popp_id)
|
|
goto done;
|
|
|
|
if (rtac_adm_data.device[dev_idx].num_of_popp ==
|
|
RTAC_MAX_ACTIVE_POPP) {
|
|
pr_err("%s, Max POPP!\n", __func__);
|
|
goto done;
|
|
}
|
|
rtac_adm_data.device[dev_idx].popp[
|
|
rtac_adm_data.device[dev_idx].num_of_popp].popp = popp_id;
|
|
rtac_adm_data.device[dev_idx].popp[
|
|
rtac_adm_data.device[dev_idx].num_of_popp].popp_topology =
|
|
q6asm_get_asm_topology(popp_id);
|
|
rtac_adm_data.device[dev_idx].popp[
|
|
rtac_adm_data.device[dev_idx].num_of_popp++].app_type =
|
|
q6asm_get_asm_app_type(popp_id);
|
|
|
|
pr_debug("%s: popp_id = %d, popp topology = 0x%x, popp app type = 0x%x\n",
|
|
__func__,
|
|
rtac_adm_data.device[dev_idx].popp[
|
|
rtac_adm_data.device[dev_idx].num_of_popp - 1].popp,
|
|
rtac_adm_data.device[dev_idx].popp[
|
|
rtac_adm_data.device[dev_idx].num_of_popp - 1].popp_topology,
|
|
rtac_adm_data.device[dev_idx].popp[
|
|
rtac_adm_data.device[dev_idx].num_of_popp - 1].app_type);
|
|
done:
|
|
return;
|
|
}
|
|
|
|
void rtac_update_afe_topology(u32 port_id)
|
|
{
|
|
u32 i = 0;
|
|
|
|
mutex_lock(&rtac_adm_mutex);
|
|
for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
|
|
if (rtac_adm_data.device[i].afe_port == port_id) {
|
|
rtac_adm_data.device[i].afe_topology =
|
|
afe_get_topology(port_id);
|
|
pr_debug("%s: port_id = 0x%x topology_id = 0x%x copp_id = %d\n",
|
|
__func__, port_id,
|
|
rtac_adm_data.device[i].afe_topology,
|
|
rtac_adm_data.device[i].copp);
|
|
}
|
|
}
|
|
mutex_unlock(&rtac_adm_mutex);
|
|
}
|
|
|
|
void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id,
|
|
u32 app_type, u32 acdb_id)
|
|
{
|
|
u32 i = 0;
|
|
|
|
pr_debug("%s: num rtac devices %d port_id = %d, copp_id = %d\n",
|
|
__func__, rtac_adm_data.num_of_dev, port_id, copp_id);
|
|
|
|
mutex_lock(&rtac_adm_mutex);
|
|
if (rtac_adm_data.num_of_dev == RTAC_MAX_ACTIVE_DEVICES) {
|
|
pr_err("%s, Can't add anymore RTAC devices!\n", __func__);
|
|
goto done;
|
|
}
|
|
|
|
/* Check if device already added */
|
|
if (rtac_adm_data.num_of_dev != 0) {
|
|
for (; i < rtac_adm_data.num_of_dev; i++) {
|
|
if (rtac_adm_data.device[i].afe_port == port_id &&
|
|
rtac_adm_data.device[i].copp == copp_id) {
|
|
add_popp(i, port_id, popp_id);
|
|
goto done;
|
|
}
|
|
if (rtac_adm_data.device[i].num_of_popp ==
|
|
RTAC_MAX_ACTIVE_POPP) {
|
|
pr_err("%s, Max POPP!\n", __func__);
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Add device */
|
|
rtac_adm_data.num_of_dev++;
|
|
|
|
rtac_adm_data.device[i].topology_id =
|
|
adm_get_topology_for_port_from_copp_id(port_id, copp_id);
|
|
rtac_adm_data.device[i].afe_topology =
|
|
afe_get_topology(port_id);
|
|
rtac_adm_data.device[i].afe_port = port_id;
|
|
rtac_adm_data.device[i].copp = copp_id;
|
|
rtac_adm_data.device[i].app_type = app_type;
|
|
rtac_adm_data.device[i].acdb_dev_id = acdb_id;
|
|
rtac_adm_data.device[i].popp[
|
|
rtac_adm_data.device[i].num_of_popp].popp = popp_id;
|
|
rtac_adm_data.device[i].popp[
|
|
rtac_adm_data.device[i].num_of_popp].popp_topology =
|
|
q6asm_get_asm_topology(popp_id);
|
|
rtac_adm_data.device[i].popp[
|
|
rtac_adm_data.device[i].num_of_popp++].app_type =
|
|
q6asm_get_asm_app_type(popp_id);
|
|
|
|
pr_debug("%s: topology = 0x%x, afe_topology = 0x%x, port_id = %d, copp_id = %d, app id = 0x%x, acdb id = %d, popp_id = %d, popp topology = 0x%x, popp app type = 0x%x\n",
|
|
__func__,
|
|
rtac_adm_data.device[i].topology_id,
|
|
rtac_adm_data.device[i].afe_topology,
|
|
rtac_adm_data.device[i].afe_port,
|
|
rtac_adm_data.device[i].copp,
|
|
rtac_adm_data.device[i].app_type,
|
|
rtac_adm_data.device[i].acdb_dev_id,
|
|
rtac_adm_data.device[i].popp[
|
|
rtac_adm_data.device[i].num_of_popp - 1].popp,
|
|
rtac_adm_data.device[i].popp[
|
|
rtac_adm_data.device[i].num_of_popp - 1].popp_topology,
|
|
rtac_adm_data.device[i].popp[
|
|
rtac_adm_data.device[i].num_of_popp - 1].app_type);
|
|
done:
|
|
mutex_unlock(&rtac_adm_mutex);
|
|
}
|
|
|
|
static void shift_adm_devices(u32 dev_idx)
|
|
{
|
|
for (; dev_idx < rtac_adm_data.num_of_dev; dev_idx++) {
|
|
memcpy(&rtac_adm_data.device[dev_idx],
|
|
&rtac_adm_data.device[dev_idx + 1],
|
|
sizeof(rtac_adm_data.device[dev_idx]));
|
|
memset(&rtac_adm_data.device[dev_idx + 1], 0,
|
|
sizeof(rtac_adm_data.device[dev_idx]));
|
|
}
|
|
}
|
|
|
|
static void shift_popp(u32 copp_idx, u32 popp_idx)
|
|
{
|
|
for (; popp_idx < rtac_adm_data.device[copp_idx].num_of_popp;
|
|
popp_idx++) {
|
|
memcpy(&rtac_adm_data.device[copp_idx].popp[popp_idx].popp,
|
|
&rtac_adm_data.device[copp_idx].popp[popp_idx + 1].
|
|
popp, sizeof(uint32_t));
|
|
memcpy(&rtac_adm_data.device[copp_idx].popp[popp_idx].
|
|
popp_topology,
|
|
&rtac_adm_data.device[copp_idx].popp[popp_idx + 1].
|
|
popp_topology,
|
|
sizeof(uint32_t));
|
|
memset(&rtac_adm_data.device[copp_idx].popp[popp_idx + 1].
|
|
popp, 0, sizeof(uint32_t));
|
|
memset(&rtac_adm_data.device[copp_idx].popp[popp_idx + 1].
|
|
popp_topology, 0, sizeof(uint32_t));
|
|
}
|
|
}
|
|
|
|
void rtac_remove_adm_device(u32 port_id, u32 copp_id)
|
|
{
|
|
s32 i;
|
|
|
|
pr_debug("%s: num rtac devices %d port_id = %d, copp_id = %d\n",
|
|
__func__, rtac_adm_data.num_of_dev, port_id, copp_id);
|
|
|
|
mutex_lock(&rtac_adm_mutex);
|
|
/* look for device */
|
|
for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
|
|
if (rtac_adm_data.device[i].afe_port == port_id &&
|
|
rtac_adm_data.device[i].copp == copp_id) {
|
|
memset(&rtac_adm_data.device[i], 0,
|
|
sizeof(rtac_adm_data.device[i]));
|
|
rtac_adm_data.num_of_dev--;
|
|
|
|
if (rtac_adm_data.num_of_dev >= 1) {
|
|
shift_adm_devices(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
mutex_unlock(&rtac_adm_mutex);
|
|
}
|
|
|
|
void rtac_remove_popp_from_adm_devices(u32 popp_id)
|
|
{
|
|
s32 i, j;
|
|
|
|
pr_debug("%s: popp_id = %d\n", __func__, popp_id);
|
|
|
|
mutex_lock(&rtac_adm_mutex);
|
|
for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
|
|
for (j = 0; j < rtac_adm_data.device[i].num_of_popp; j++) {
|
|
if (rtac_adm_data.device[i].popp[j].popp ==
|
|
popp_id) {
|
|
rtac_adm_data.device[i].popp[j].popp = 0;
|
|
rtac_adm_data.device[i].popp[j].
|
|
popp_topology = 0;
|
|
rtac_adm_data.device[i].num_of_popp--;
|
|
shift_popp(i, j);
|
|
}
|
|
}
|
|
}
|
|
mutex_unlock(&rtac_adm_mutex);
|
|
}
|
|
|
|
|
|
/* Voice Info */
|
|
static void set_rtac_voice_data(int idx, u32 cvs_handle, u32 cvp_handle,
|
|
u32 rx_afe_port, u32 tx_afe_port,
|
|
u32 rx_acdb_id, u32 tx_acdb_id,
|
|
u32 session_id)
|
|
{
|
|
rtac_voice_data.voice[idx].tx_topology_id =
|
|
voice_get_topology(CVP_VOC_TX_TOPOLOGY_CAL);
|
|
rtac_voice_data.voice[idx].rx_topology_id =
|
|
voice_get_topology(CVP_VOC_RX_TOPOLOGY_CAL);
|
|
rtac_voice_data.voice[idx].tx_afe_topology =
|
|
afe_get_topology(tx_afe_port);
|
|
rtac_voice_data.voice[idx].rx_afe_topology =
|
|
afe_get_topology(rx_afe_port);
|
|
rtac_voice_data.voice[idx].tx_afe_port = tx_afe_port;
|
|
rtac_voice_data.voice[idx].rx_afe_port = rx_afe_port;
|
|
rtac_voice_data.voice[idx].tx_acdb_id = tx_acdb_id;
|
|
rtac_voice_data.voice[idx].rx_acdb_id = rx_acdb_id;
|
|
rtac_voice_data.voice[idx].cvs_handle = cvs_handle;
|
|
rtac_voice_data.voice[idx].cvp_handle = cvp_handle;
|
|
pr_debug("%s\n%s: %x\n%s: %d %s: %d\n%s: %d %s: %d\n %s: %d\n %s: %d\n%s: %d %s: %d\n%s",
|
|
"<---- Voice Data Info ---->", "Session id", session_id,
|
|
"cvs_handle", cvs_handle, "cvp_handle", cvp_handle,
|
|
"rx_afe_topology", rtac_voice_data.voice[idx].rx_afe_topology,
|
|
"tx_afe_topology", rtac_voice_data.voice[idx].tx_afe_topology,
|
|
"rx_afe_port", rx_afe_port, "tx_afe_port", tx_afe_port,
|
|
"rx_acdb_id", rx_acdb_id, "tx_acdb_id", tx_acdb_id,
|
|
"<-----------End----------->");
|
|
|
|
/* Store session ID for voice RTAC */
|
|
voice_session_id[idx] = session_id;
|
|
}
|
|
|
|
void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
|
|
u32 tx_afe_port, u32 rx_acdb_id, u32 tx_acdb_id,
|
|
u32 session_id)
|
|
{
|
|
u32 i = 0;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
mutex_lock(&rtac_voice_mutex);
|
|
|
|
if (rtac_voice_data.num_of_voice_combos ==
|
|
RTAC_MAX_ACTIVE_VOICE_COMBOS) {
|
|
pr_err("%s, Can't add anymore RTAC devices!\n", __func__);
|
|
goto done;
|
|
}
|
|
|
|
/* Check if device already added */
|
|
if (rtac_voice_data.num_of_voice_combos != 0) {
|
|
for (; i < rtac_voice_data.num_of_voice_combos; i++) {
|
|
if (rtac_voice_data.voice[i].cvs_handle ==
|
|
cvs_handle) {
|
|
set_rtac_voice_data(i, cvs_handle, cvp_handle,
|
|
rx_afe_port, tx_afe_port, rx_acdb_id,
|
|
tx_acdb_id, session_id);
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Add device */
|
|
rtac_voice_data.num_of_voice_combos++;
|
|
set_rtac_voice_data(i, cvs_handle, cvp_handle,
|
|
rx_afe_port, tx_afe_port,
|
|
rx_acdb_id, tx_acdb_id,
|
|
session_id);
|
|
done:
|
|
mutex_unlock(&rtac_voice_mutex);
|
|
}
|
|
|
|
static void shift_voice_devices(u32 idx)
|
|
{
|
|
for (; idx < rtac_voice_data.num_of_voice_combos - 1; idx++) {
|
|
memcpy(&rtac_voice_data.voice[idx],
|
|
&rtac_voice_data.voice[idx + 1],
|
|
sizeof(rtac_voice_data.voice[idx]));
|
|
voice_session_id[idx] = voice_session_id[idx + 1];
|
|
}
|
|
}
|
|
|
|
void rtac_remove_voice(u32 cvs_handle)
|
|
{
|
|
u32 i = 0;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
|
|
mutex_lock(&rtac_voice_mutex);
|
|
/* look for device */
|
|
for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
|
|
if (rtac_voice_data.voice[i].cvs_handle == cvs_handle) {
|
|
shift_voice_devices(i);
|
|
rtac_voice_data.num_of_voice_combos--;
|
|
memset(&rtac_voice_data.voice[
|
|
rtac_voice_data.num_of_voice_combos], 0,
|
|
sizeof(rtac_voice_data.voice
|
|
[rtac_voice_data.num_of_voice_combos]));
|
|
voice_session_id[rtac_voice_data.num_of_voice_combos]
|
|
= 0;
|
|
break;
|
|
}
|
|
}
|
|
mutex_unlock(&rtac_voice_mutex);
|
|
}
|
|
|
|
static u32 get_voice_session_id_cvs(u32 cvs_handle)
|
|
{
|
|
u32 i;
|
|
|
|
for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
|
|
if (rtac_voice_data.voice[i].cvs_handle == cvs_handle)
|
|
return voice_session_id[i];
|
|
}
|
|
|
|
pr_err("%s: No voice index for CVS handle %d found returning 0\n",
|
|
__func__, cvs_handle);
|
|
return 0;
|
|
}
|
|
|
|
static u32 get_voice_session_id_cvp(u32 cvp_handle)
|
|
{
|
|
u32 i;
|
|
|
|
for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
|
|
if (rtac_voice_data.voice[i].cvp_handle == cvp_handle)
|
|
return voice_session_id[i];
|
|
}
|
|
|
|
pr_err("%s: No voice index for CVP handle %d found returning 0\n",
|
|
__func__, cvp_handle);
|
|
return 0;
|
|
}
|
|
|
|
static int get_voice_index(u32 mode, u32 handle)
|
|
{
|
|
if (mode == RTAC_CVP)
|
|
return voice_get_idx_for_session(
|
|
get_voice_session_id_cvp(handle));
|
|
if (mode == RTAC_CVS)
|
|
return voice_get_idx_for_session(
|
|
get_voice_session_id_cvs(handle));
|
|
|
|
pr_err("%s: Invalid mode %d, returning 0\n",
|
|
__func__, mode);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* ADM APR */
|
|
void rtac_set_adm_handle(void *handle)
|
|
{
|
|
pr_debug("%s: handle = %pK\n", __func__, handle);
|
|
|
|
mutex_lock(&rtac_adm_apr_mutex);
|
|
rtac_adm_apr_data.apr_handle = handle;
|
|
mutex_unlock(&rtac_adm_apr_mutex);
|
|
}
|
|
|
|
bool rtac_make_adm_callback(uint32_t *payload, u32 payload_size)
|
|
{
|
|
pr_debug("%s:cmd_state = %d\n", __func__,
|
|
atomic_read(&rtac_adm_apr_data.cmd_state));
|
|
if (atomic_read(&rtac_adm_apr_data.cmd_state) != 1)
|
|
return false;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
if (payload_size == sizeof(uint32_t))
|
|
atomic_set(&rtac_common.apr_err_code, payload[0]);
|
|
else if (payload_size == (2*sizeof(uint32_t)))
|
|
atomic_set(&rtac_common.apr_err_code, payload[1]);
|
|
|
|
atomic_set(&rtac_adm_apr_data.cmd_state, 0);
|
|
wake_up(&rtac_adm_apr_data.cmd_wait);
|
|
return true;
|
|
}
|
|
|
|
int send_adm_apr(void *buf, u32 opcode)
|
|
{
|
|
s32 result;
|
|
u32 user_buf_size = 0;
|
|
u32 bytes_returned = 0;
|
|
u32 copp_id;
|
|
u32 payload_size;
|
|
u32 data_size = 0;
|
|
int copp_idx;
|
|
int port_idx;
|
|
struct apr_hdr adm_params;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
|
|
if (rtac_cal[ADM_RTAC_CAL].map_data.dma_buf == NULL) {
|
|
result = rtac_allocate_cal_buffer(ADM_RTAC_CAL);
|
|
if (result < 0) {
|
|
pr_err("%s: allocate buffer failed!",
|
|
__func__);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (rtac_cal[ADM_RTAC_CAL].map_data.map_handle == 0) {
|
|
result = rtac_map_cal_buffer(ADM_RTAC_CAL);
|
|
if (result < 0) {
|
|
pr_err("%s: map buffer failed!",
|
|
__func__);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (copy_from_user(&user_buf_size, (void *)buf,
|
|
sizeof(user_buf_size))) {
|
|
pr_err("%s: Copy from user failed! buf = 0x%pK\n",
|
|
__func__, buf);
|
|
goto done;
|
|
}
|
|
if (user_buf_size <= 0) {
|
|
pr_err("%s: Invalid buffer size = %d\n",
|
|
__func__, user_buf_size);
|
|
goto done;
|
|
}
|
|
|
|
if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
|
|
pr_err("%s: Could not copy payload size from user buffer\n",
|
|
__func__);
|
|
goto done;
|
|
}
|
|
|
|
if (copy_from_user(&copp_id, buf + 2 * sizeof(u32), sizeof(u32))) {
|
|
pr_err("%s: Could not copy port id from user buffer\n",
|
|
__func__);
|
|
goto done;
|
|
}
|
|
|
|
if (adm_get_indexes_from_copp_id(copp_id, &copp_idx, &port_idx) != 0) {
|
|
pr_err("%s: Copp Id-%d is not active\n", __func__, copp_id);
|
|
goto done;
|
|
}
|
|
|
|
mutex_lock(&rtac_adm_apr_mutex);
|
|
if (rtac_adm_apr_data.apr_handle == NULL) {
|
|
pr_err("%s: APR not initialized\n", __func__);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
if (opcode == ADM_CMD_SET_PP_PARAMS_V5) {
|
|
/* set payload size to in-band payload */
|
|
/* set data size to actual out of band payload size */
|
|
data_size = payload_size - 4 * sizeof(u32);
|
|
if (data_size > rtac_cal[ADM_RTAC_CAL].map_data.map_size) {
|
|
pr_err("%s: Invalid data size = %d\n",
|
|
__func__, data_size);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
payload_size = 4 * sizeof(u32);
|
|
|
|
/* Copy buffer to out-of-band payload */
|
|
if (copy_from_user((void *)
|
|
rtac_cal[ADM_RTAC_CAL].cal_data.kvaddr,
|
|
buf + 7 * sizeof(u32), data_size)) {
|
|
pr_err("%s: Could not copy payload from user buffer\n",
|
|
__func__);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
/* set payload size in packet */
|
|
rtac_adm_buffer[8] = data_size;
|
|
} else {
|
|
if (payload_size > MAX_PAYLOAD_SIZE) {
|
|
pr_err("%s: Invalid payload size = %d\n",
|
|
__func__, payload_size);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
/* Copy buffer to in-band payload */
|
|
if (copy_from_user(rtac_adm_buffer +
|
|
sizeof(adm_params)/sizeof(u32),
|
|
buf + 3 * sizeof(u32), payload_size)) {
|
|
pr_err("%s: Could not copy payload from user buffer\n",
|
|
__func__);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
/* Pack header */
|
|
adm_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
|
|
APR_HDR_LEN(20), APR_PKT_VER);
|
|
adm_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
|
|
payload_size);
|
|
adm_params.src_svc = APR_SVC_ADM;
|
|
adm_params.src_domain = APR_DOMAIN_APPS;
|
|
adm_params.src_port = copp_id;
|
|
adm_params.dest_svc = APR_SVC_ADM;
|
|
adm_params.dest_domain = APR_DOMAIN_ADSP;
|
|
adm_params.dest_port = copp_id;
|
|
adm_params.token = port_idx << 16 | copp_idx;
|
|
adm_params.opcode = opcode;
|
|
|
|
/* fill for out-of-band */
|
|
rtac_adm_buffer[5] =
|
|
lower_32_bits(rtac_cal[ADM_RTAC_CAL].cal_data.paddr);
|
|
rtac_adm_buffer[6] =
|
|
msm_audio_populate_upper_32_bits(
|
|
rtac_cal[ADM_RTAC_CAL].cal_data.paddr);
|
|
rtac_adm_buffer[7] = rtac_cal[ADM_RTAC_CAL].map_data.map_handle;
|
|
|
|
memcpy(rtac_adm_buffer, &adm_params, sizeof(adm_params));
|
|
atomic_set(&rtac_adm_apr_data.cmd_state, 1);
|
|
|
|
pr_debug("%s: Sending RTAC command ioctl 0x%x, paddr 0x%pK\n",
|
|
__func__, opcode,
|
|
&rtac_cal[ADM_RTAC_CAL].cal_data.paddr);
|
|
|
|
result = apr_send_pkt(rtac_adm_apr_data.apr_handle,
|
|
(uint32_t *)rtac_adm_buffer);
|
|
if (result < 0) {
|
|
pr_err("%s: Set params failed copp = %d\n", __func__, copp_id);
|
|
goto err;
|
|
}
|
|
/* Wait for the callback */
|
|
result = wait_event_timeout(rtac_adm_apr_data.cmd_wait,
|
|
(atomic_read(&rtac_adm_apr_data.cmd_state) == 0),
|
|
msecs_to_jiffies(TIMEOUT_MS));
|
|
if (!result) {
|
|
pr_err("%s: Set params timed out copp = %d\n", __func__,
|
|
copp_id);
|
|
goto err;
|
|
}
|
|
if (atomic_read(&rtac_common.apr_err_code)) {
|
|
pr_err("%s: DSP returned error code = [%s], opcode = 0x%x\n",
|
|
__func__, adsp_err_get_err_str(atomic_read(
|
|
&rtac_common.apr_err_code)),
|
|
opcode);
|
|
result = adsp_err_get_lnx_err_code(
|
|
atomic_read(
|
|
&rtac_common.apr_err_code));
|
|
goto err;
|
|
}
|
|
|
|
if (opcode == ADM_CMD_GET_PP_PARAMS_V5) {
|
|
bytes_returned = ((u32 *)rtac_cal[ADM_RTAC_CAL].cal_data.
|
|
kvaddr)[2] + 3 * sizeof(u32);
|
|
|
|
if (bytes_returned > rtac_cal[ADM_RTAC_CAL].
|
|
map_data.map_size) {
|
|
pr_err("%s: Invalid data size = %d\n",
|
|
__func__, bytes_returned);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
if (bytes_returned > user_buf_size) {
|
|
pr_err("%s: User buf not big enough, size = 0x%x, returned size = 0x%x\n",
|
|
__func__, user_buf_size, bytes_returned);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
if (copy_to_user(buf, (void *)
|
|
rtac_cal[ADM_RTAC_CAL].cal_data.kvaddr,
|
|
bytes_returned)) {
|
|
pr_err("%s: Could not copy buffer to user,size = %d\n",
|
|
__func__, bytes_returned);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
} else {
|
|
bytes_returned = data_size;
|
|
}
|
|
mutex_unlock(&rtac_adm_apr_mutex);
|
|
done:
|
|
return bytes_returned;
|
|
err:
|
|
mutex_unlock(&rtac_adm_apr_mutex);
|
|
return result;
|
|
}
|
|
|
|
|
|
/* ASM APR */
|
|
void rtac_set_asm_handle(u32 session_id, void *handle)
|
|
{
|
|
pr_debug("%s\n", __func__);
|
|
|
|
mutex_lock(&rtac_asm_apr_mutex);
|
|
rtac_asm_apr_data[session_id].apr_handle = handle;
|
|
mutex_unlock(&rtac_asm_apr_mutex);
|
|
}
|
|
|
|
bool rtac_make_asm_callback(u32 session_id, uint32_t *payload,
|
|
u32 payload_size)
|
|
{
|
|
if (atomic_read(&rtac_asm_apr_data[session_id].cmd_state) != 1)
|
|
return false;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
if (payload_size == sizeof(uint32_t))
|
|
atomic_set(&rtac_common.apr_err_code, payload[0]);
|
|
else if (payload_size == (2*sizeof(uint32_t)))
|
|
atomic_set(&rtac_common.apr_err_code, payload[1]);
|
|
|
|
atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 0);
|
|
wake_up(&rtac_asm_apr_data[session_id].cmd_wait);
|
|
return true;
|
|
}
|
|
|
|
int send_rtac_asm_apr(void *buf, u32 opcode)
|
|
{
|
|
s32 result;
|
|
u32 user_buf_size = 0;
|
|
u32 bytes_returned = 0;
|
|
u32 session_id = 0;
|
|
u32 payload_size;
|
|
u32 data_size = 0;
|
|
struct apr_hdr asm_params;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
|
|
if (rtac_cal[ASM_RTAC_CAL].map_data.dma_buf == NULL) {
|
|
result = rtac_allocate_cal_buffer(ASM_RTAC_CAL);
|
|
if (result < 0) {
|
|
pr_err("%s: allocate buffer failed!",
|
|
__func__);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (rtac_cal[ASM_RTAC_CAL].map_data.map_handle == 0) {
|
|
result = rtac_map_cal_buffer(ASM_RTAC_CAL);
|
|
if (result < 0) {
|
|
pr_err("%s: map buffer failed!",
|
|
__func__);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (copy_from_user(&user_buf_size, (void *)buf,
|
|
sizeof(user_buf_size))) {
|
|
pr_err("%s: Copy from user failed! buf = 0x%pK\n",
|
|
__func__, buf);
|
|
goto done;
|
|
}
|
|
if (user_buf_size <= 0) {
|
|
pr_err("%s: Invalid buffer size = %d\n",
|
|
__func__, user_buf_size);
|
|
goto done;
|
|
}
|
|
|
|
if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
|
|
pr_err("%s: Could not copy payload size from user buffer\n",
|
|
__func__);
|
|
goto done;
|
|
}
|
|
|
|
if (copy_from_user(&session_id, buf + 2 * sizeof(u32), sizeof(u32))) {
|
|
pr_err("%s: Could not copy session id from user buffer\n",
|
|
__func__);
|
|
goto done;
|
|
}
|
|
if (session_id >= (ASM_ACTIVE_STREAMS_ALLOWED + 1)) {
|
|
pr_err("%s: Invalid Session = %d\n", __func__, session_id);
|
|
goto done;
|
|
}
|
|
|
|
mutex_lock(&rtac_asm_apr_mutex);
|
|
if (rtac_asm_apr_data[session_id].apr_handle == NULL) {
|
|
pr_err("%s: APR not initialized\n", __func__);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
if (opcode == ASM_STREAM_CMD_SET_PP_PARAMS_V2) {
|
|
/* set payload size to in-band payload */
|
|
/* set data size to actual out of band payload size */
|
|
data_size = payload_size - 4 * sizeof(u32);
|
|
if (data_size > rtac_cal[ASM_RTAC_CAL].map_data.map_size) {
|
|
pr_err("%s: Invalid data size = %d\n",
|
|
__func__, data_size);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
payload_size = 4 * sizeof(u32);
|
|
|
|
/* Copy buffer to out-of-band payload */
|
|
if (copy_from_user((void *)
|
|
rtac_cal[ASM_RTAC_CAL].cal_data.kvaddr,
|
|
buf + 7 * sizeof(u32), data_size)) {
|
|
pr_err("%s: Could not copy payload from user buffer\n",
|
|
__func__);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
/* set payload size in packet */
|
|
rtac_asm_buffer[8] = data_size;
|
|
|
|
} else {
|
|
if (payload_size > MAX_PAYLOAD_SIZE) {
|
|
pr_err("%s: Invalid payload size = %d\n",
|
|
__func__, payload_size);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
/* Copy buffer to in-band payload */
|
|
if (copy_from_user(rtac_asm_buffer +
|
|
sizeof(asm_params)/sizeof(u32),
|
|
buf + 3 * sizeof(u32), payload_size)) {
|
|
pr_err("%s: Could not copy payload from user buffer\n",
|
|
__func__);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
/* Pack header */
|
|
asm_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
|
|
APR_HDR_LEN(20), APR_PKT_VER);
|
|
asm_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
|
|
payload_size);
|
|
asm_params.src_svc = q6asm_get_apr_service_id(session_id);
|
|
asm_params.src_domain = APR_DOMAIN_APPS;
|
|
asm_params.src_port = (session_id << 8) | 0x0001;
|
|
asm_params.dest_svc = APR_SVC_ASM;
|
|
asm_params.dest_domain = APR_DOMAIN_ADSP;
|
|
asm_params.dest_port = (session_id << 8) | 0x0001;
|
|
asm_params.token = session_id;
|
|
asm_params.opcode = opcode;
|
|
|
|
/* fill for out-of-band */
|
|
rtac_asm_buffer[5] =
|
|
lower_32_bits(rtac_cal[ASM_RTAC_CAL].cal_data.paddr);
|
|
rtac_asm_buffer[6] =
|
|
msm_audio_populate_upper_32_bits(
|
|
rtac_cal[ASM_RTAC_CAL].cal_data.paddr);
|
|
rtac_asm_buffer[7] = rtac_cal[ASM_RTAC_CAL].map_data.map_handle;
|
|
|
|
memcpy(rtac_asm_buffer, &asm_params, sizeof(asm_params));
|
|
atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 1);
|
|
|
|
pr_debug("%s: Sending RTAC command ioctl 0x%x, paddr 0x%pK\n",
|
|
__func__, opcode,
|
|
&rtac_cal[ASM_RTAC_CAL].cal_data.paddr);
|
|
|
|
result = apr_send_pkt(rtac_asm_apr_data[session_id].apr_handle,
|
|
(uint32_t *)rtac_asm_buffer);
|
|
if (result < 0) {
|
|
pr_err("%s: Set params failed session = %d\n",
|
|
__func__, session_id);
|
|
goto err;
|
|
}
|
|
|
|
/* Wait for the callback */
|
|
result = wait_event_timeout(rtac_asm_apr_data[session_id].cmd_wait,
|
|
(atomic_read(&rtac_asm_apr_data[session_id].cmd_state) == 0),
|
|
5 * HZ);
|
|
if (!result) {
|
|
pr_err("%s: Set params timed out session = %d\n",
|
|
__func__, session_id);
|
|
goto err;
|
|
}
|
|
if (atomic_read(&rtac_common.apr_err_code)) {
|
|
pr_err("%s: DSP returned error code = [%s], opcode = 0x%x\n",
|
|
__func__, adsp_err_get_err_str(atomic_read(
|
|
&rtac_common.apr_err_code)),
|
|
opcode);
|
|
result = adsp_err_get_lnx_err_code(
|
|
atomic_read(
|
|
&rtac_common.apr_err_code));
|
|
goto err;
|
|
}
|
|
|
|
if (opcode == ASM_STREAM_CMD_GET_PP_PARAMS_V2) {
|
|
bytes_returned = ((u32 *)rtac_cal[ASM_RTAC_CAL].cal_data.
|
|
kvaddr)[2] + 3 * sizeof(u32);
|
|
|
|
if (bytes_returned > rtac_cal[ASM_RTAC_CAL].
|
|
map_data.map_size) {
|
|
pr_err("%s: Invalid data size = %d\n",
|
|
__func__, bytes_returned);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
if (bytes_returned > user_buf_size) {
|
|
pr_err("%s: User buf not big enough, size = 0x%x, returned size = 0x%x\n",
|
|
__func__, user_buf_size, bytes_returned);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
if (copy_to_user(buf, (void *)
|
|
rtac_cal[ASM_RTAC_CAL].cal_data.kvaddr,
|
|
bytes_returned)) {
|
|
pr_err("%s: Could not copy buffer to user,size = %d\n",
|
|
__func__, bytes_returned);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
} else {
|
|
bytes_returned = data_size;
|
|
}
|
|
mutex_unlock(&rtac_asm_apr_mutex);
|
|
done:
|
|
return bytes_returned;
|
|
err:
|
|
mutex_unlock(&rtac_asm_apr_mutex);
|
|
return result;
|
|
}
|
|
|
|
/* AFE APR */
|
|
void rtac_set_afe_handle(void *handle)
|
|
{
|
|
mutex_lock(&rtac_afe_apr_mutex);
|
|
rtac_afe_apr_data.apr_handle = handle;
|
|
mutex_unlock(&rtac_afe_apr_mutex);
|
|
}
|
|
|
|
bool rtac_make_afe_callback(uint32_t *payload, uint32_t payload_size)
|
|
{
|
|
pr_debug("%s:cmd_state = %d\n", __func__,
|
|
atomic_read(&rtac_afe_apr_data.cmd_state));
|
|
if (atomic_read(&rtac_afe_apr_data.cmd_state) != 1)
|
|
return false;
|
|
|
|
if (payload_size == sizeof(uint32_t))
|
|
atomic_set(&rtac_common.apr_err_code, payload[0]);
|
|
else if (payload_size == (2*sizeof(uint32_t)))
|
|
atomic_set(&rtac_common.apr_err_code, payload[1]);
|
|
|
|
atomic_set(&rtac_afe_apr_data.cmd_state, 0);
|
|
wake_up(&rtac_afe_apr_data.cmd_wait);
|
|
return true;
|
|
}
|
|
|
|
static int fill_afe_apr_hdr(struct apr_hdr *apr_hdr, uint32_t port,
|
|
uint32_t opcode, uint32_t apr_msg_size)
|
|
{
|
|
if (apr_hdr == NULL) {
|
|
pr_err("%s: invalid APR pointer", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
apr_hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
|
|
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
|
|
apr_hdr->pkt_size = apr_msg_size;
|
|
apr_hdr->src_svc = APR_SVC_AFE;
|
|
apr_hdr->src_domain = APR_DOMAIN_APPS;
|
|
apr_hdr->src_port = 0;
|
|
apr_hdr->dest_svc = APR_SVC_AFE;
|
|
apr_hdr->dest_domain = APR_DOMAIN_ADSP;
|
|
apr_hdr->dest_port = 0;
|
|
apr_hdr->token = port;
|
|
apr_hdr->opcode = opcode;
|
|
|
|
return 0;
|
|
|
|
}
|
|
static int send_rtac_afe_apr(void *buf, uint32_t opcode)
|
|
{
|
|
int32_t result;
|
|
uint32_t bytes_returned = 0;
|
|
uint32_t port_index = 0;
|
|
uint32_t apr_msg_size = 0;
|
|
struct rtac_afe_user_data user_afe_buf;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
|
|
if (rtac_cal[AFE_RTAC_CAL].map_data.dma_buf == NULL) {
|
|
result = rtac_allocate_cal_buffer(AFE_RTAC_CAL);
|
|
if (result < 0) {
|
|
pr_err("%s: allocate buffer failed! ret = %d\n",
|
|
__func__, result);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (rtac_cal[AFE_RTAC_CAL].map_data.map_handle == 0) {
|
|
result = rtac_map_cal_buffer(AFE_RTAC_CAL);
|
|
if (result < 0) {
|
|
pr_err("%s: map buffer failed! ret = %d\n",
|
|
__func__, result);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (copy_from_user(&user_afe_buf, (void *)buf,
|
|
sizeof(struct rtac_afe_user_data))) {
|
|
pr_err("%s: Copy from user failed! buf = 0x%pK\n",
|
|
__func__, buf);
|
|
goto done;
|
|
}
|
|
|
|
if (user_afe_buf.buf_size <= 0) {
|
|
pr_err("%s: Invalid buffer size = %d\n",
|
|
__func__, user_afe_buf.buf_size);
|
|
goto done;
|
|
}
|
|
|
|
port_index = q6audio_get_port_index(user_afe_buf.port_id);
|
|
if (port_index >= AFE_MAX_PORTS) {
|
|
pr_err("%s: Invalid AFE port = 0x%x\n",
|
|
__func__, user_afe_buf.port_id);
|
|
goto done;
|
|
}
|
|
|
|
mutex_lock(&rtac_afe_apr_mutex);
|
|
if (rtac_afe_apr_data.apr_handle == NULL) {
|
|
pr_err("%s: APR not initialized\n", __func__);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
if (opcode == AFE_PORT_CMD_SET_PARAM_V2) {
|
|
struct afe_port_cmd_set_param_v2 *afe_set_apr_msg;
|
|
|
|
/* set data size to actual out of band payload size */
|
|
if (user_afe_buf.rtac_afe_set.cmd.payload_size >
|
|
rtac_cal[AFE_RTAC_CAL].map_data.map_size) {
|
|
pr_err("%s: Invalid data size = %d\n",
|
|
__func__,
|
|
user_afe_buf.rtac_afe_set.cmd.payload_size);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
/* Copy buffer to out-of-band payload */
|
|
if (copy_from_user((void *)
|
|
rtac_cal[AFE_RTAC_CAL].cal_data.kvaddr,
|
|
buf+offsetof(struct rtac_afe_user_data,
|
|
rtac_afe_set.data),
|
|
user_afe_buf.rtac_afe_set.cmd.payload_size)) {
|
|
pr_err("%s: Could not copy payload from user buffer\n",
|
|
__func__);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
/* Copy AFE APR Message */
|
|
afe_set_apr_msg = (struct afe_port_cmd_set_param_v2 *)
|
|
((u8 *)rtac_afe_buffer +
|
|
sizeof(struct apr_hdr));
|
|
if (copy_from_user((void *)
|
|
afe_set_apr_msg,
|
|
buf + offsetof(struct rtac_afe_user_data,
|
|
rtac_afe_set.cmd),
|
|
sizeof(struct afe_port_cmd_set_param_v2))) {
|
|
pr_err("%s: Could not copy payload from user buffer\n",
|
|
__func__);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
afe_set_apr_msg->payload_address_lsw =
|
|
lower_32_bits(rtac_cal[AFE_RTAC_CAL].cal_data.paddr);
|
|
afe_set_apr_msg->payload_address_msw =
|
|
msm_audio_populate_upper_32_bits(
|
|
rtac_cal[AFE_RTAC_CAL].cal_data.paddr);
|
|
afe_set_apr_msg->mem_map_handle =
|
|
rtac_cal[AFE_RTAC_CAL].map_data.map_handle;
|
|
|
|
apr_msg_size = sizeof(struct apr_hdr) +
|
|
sizeof(struct afe_port_cmd_set_param_v2);
|
|
|
|
} else {
|
|
struct afe_port_cmd_get_param_v2 *afe_get_apr_msg;
|
|
|
|
if (user_afe_buf.cmd_size > MAX_PAYLOAD_SIZE) {
|
|
pr_err("%s: Invalid payload size = %d\n",
|
|
__func__, user_afe_buf.cmd_size);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
/* Copy buffer to in-band payload */
|
|
afe_get_apr_msg = (struct afe_port_cmd_get_param_v2 *)
|
|
((u8 *) rtac_afe_buffer +
|
|
sizeof(struct apr_hdr));
|
|
if (copy_from_user((void *)afe_get_apr_msg,
|
|
buf+offsetof(struct rtac_afe_user_data,
|
|
rtac_afe_get.cmd),
|
|
sizeof(struct afe_port_cmd_get_param_v2))) {
|
|
pr_err("%s: Could not copy payload from user buffer\n",
|
|
__func__);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
afe_get_apr_msg->payload_address_lsw =
|
|
lower_32_bits(rtac_cal[AFE_RTAC_CAL].cal_data.paddr);
|
|
afe_get_apr_msg->payload_address_msw =
|
|
msm_audio_populate_upper_32_bits(
|
|
rtac_cal[AFE_RTAC_CAL].cal_data.paddr);
|
|
afe_get_apr_msg->mem_map_handle =
|
|
rtac_cal[AFE_RTAC_CAL].map_data.map_handle;
|
|
afe_get_apr_msg->payload_size -= sizeof(struct apr_hdr);
|
|
apr_msg_size = sizeof(struct apr_hdr) +
|
|
sizeof(struct afe_port_cmd_get_param_v2);
|
|
}
|
|
|
|
fill_afe_apr_hdr((struct apr_hdr *) rtac_afe_buffer,
|
|
port_index, opcode, apr_msg_size);
|
|
|
|
atomic_set(&rtac_afe_apr_data.cmd_state, 1);
|
|
|
|
pr_debug("%s: Sending RTAC command ioctl 0x%x, paddr 0x%pK\n",
|
|
__func__, opcode,
|
|
&rtac_cal[AFE_RTAC_CAL].cal_data.paddr);
|
|
|
|
result = apr_send_pkt(rtac_afe_apr_data.apr_handle,
|
|
(uint32_t *)rtac_afe_buffer);
|
|
if (result < 0) {
|
|
pr_err("%s: Set params failed port = 0x%x, ret = %d\n",
|
|
__func__, user_afe_buf.port_id, result);
|
|
goto err;
|
|
}
|
|
/* Wait for the callback */
|
|
result = wait_event_timeout(rtac_afe_apr_data.cmd_wait,
|
|
(atomic_read(&rtac_afe_apr_data.cmd_state) == 0),
|
|
msecs_to_jiffies(TIMEOUT_MS));
|
|
if (!result) {
|
|
pr_err("%s: Set params timed out port = 0x%x, ret = %d\n",
|
|
__func__, user_afe_buf.port_id, result);
|
|
goto err;
|
|
}
|
|
if (atomic_read(&rtac_common.apr_err_code)) {
|
|
pr_err("%s: DSP returned error code = [%s], opcode = 0x%x\n",
|
|
__func__, adsp_err_get_err_str(atomic_read(
|
|
&rtac_common.apr_err_code)),
|
|
opcode);
|
|
result = adsp_err_get_lnx_err_code(
|
|
atomic_read(
|
|
&rtac_common.apr_err_code));
|
|
goto err;
|
|
}
|
|
|
|
if (opcode == AFE_PORT_CMD_GET_PARAM_V2) {
|
|
struct afe_port_param_data_v2 *get_resp;
|
|
|
|
get_resp = (struct afe_port_param_data_v2 *)
|
|
rtac_cal[AFE_RTAC_CAL].cal_data.kvaddr;
|
|
|
|
bytes_returned = get_resp->param_size +
|
|
sizeof(struct afe_port_param_data_v2);
|
|
|
|
if (bytes_returned > rtac_cal[AFE_RTAC_CAL].
|
|
map_data.map_size) {
|
|
pr_err("%s: Invalid data size = %d\n",
|
|
__func__, bytes_returned);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
if (bytes_returned > user_afe_buf.buf_size) {
|
|
pr_err("%s: user size = 0x%x, returned size = 0x%x\n",
|
|
__func__, user_afe_buf.buf_size,
|
|
bytes_returned);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
if (copy_to_user(buf, (void *)
|
|
rtac_cal[AFE_RTAC_CAL].cal_data.kvaddr,
|
|
bytes_returned)) {
|
|
pr_err("%s: Could not copy buffer to user,size = %d\n",
|
|
__func__, bytes_returned);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
} else {
|
|
bytes_returned = user_afe_buf.rtac_afe_set.cmd.payload_size;
|
|
}
|
|
mutex_unlock(&rtac_afe_apr_mutex);
|
|
done:
|
|
return bytes_returned;
|
|
err:
|
|
mutex_unlock(&rtac_afe_apr_mutex);
|
|
return result;
|
|
}
|
|
|
|
/* Voice APR */
|
|
void rtac_set_voice_handle(u32 mode, void *handle)
|
|
{
|
|
pr_debug("%s\n", __func__);
|
|
|
|
mutex_lock(&rtac_voice_apr_mutex);
|
|
rtac_voice_apr_data[mode].apr_handle = handle;
|
|
mutex_unlock(&rtac_voice_apr_mutex);
|
|
}
|
|
|
|
bool rtac_make_voice_callback(u32 mode, uint32_t *payload, u32 payload_size)
|
|
{
|
|
if ((atomic_read(&rtac_voice_apr_data[mode].cmd_state) != 1) ||
|
|
(mode >= RTAC_VOICE_MODES))
|
|
return false;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
if (payload_size == sizeof(uint32_t))
|
|
atomic_set(&rtac_common.apr_err_code, payload[0]);
|
|
else if (payload_size == (2*sizeof(uint32_t)))
|
|
atomic_set(&rtac_common.apr_err_code, payload[1]);
|
|
|
|
atomic_set(&rtac_voice_apr_data[mode].cmd_state, 0);
|
|
wake_up(&rtac_voice_apr_data[mode].cmd_wait);
|
|
return true;
|
|
}
|
|
|
|
int send_voice_apr(u32 mode, void *buf, u32 opcode)
|
|
{
|
|
s32 result;
|
|
u32 user_buf_size = 0;
|
|
u32 bytes_returned = 0;
|
|
u32 payload_size;
|
|
u32 dest_port;
|
|
u32 data_size = 0;
|
|
struct apr_hdr voice_params;
|
|
|
|
pr_debug("%s\n", __func__);
|
|
|
|
if (rtac_cal[VOICE_RTAC_CAL].map_data.dma_buf == NULL) {
|
|
result = rtac_allocate_cal_buffer(VOICE_RTAC_CAL);
|
|
if (result < 0) {
|
|
pr_err("%s: allocate buffer failed!",
|
|
__func__);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (rtac_cal[VOICE_RTAC_CAL].map_data.map_handle == 0) {
|
|
result = rtac_map_cal_buffer(VOICE_RTAC_CAL);
|
|
if (result < 0) {
|
|
pr_err("%s: map buffer failed!",
|
|
__func__);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (copy_from_user(&user_buf_size, (void *)buf,
|
|
sizeof(user_buf_size))) {
|
|
pr_err("%s: Copy from user failed! buf = 0x%pK\n",
|
|
__func__, buf);
|
|
goto done;
|
|
}
|
|
if (user_buf_size <= 0) {
|
|
pr_err("%s: Invalid buffer size = %d\n",
|
|
__func__, user_buf_size);
|
|
goto done;
|
|
}
|
|
|
|
if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
|
|
pr_err("%s: Could not copy payload size from user buffer\n",
|
|
__func__);
|
|
goto done;
|
|
}
|
|
|
|
if (copy_from_user(&dest_port, buf + 2 * sizeof(u32), sizeof(u32))) {
|
|
pr_err("%s: Could not copy port id from user buffer\n",
|
|
__func__);
|
|
goto done;
|
|
}
|
|
|
|
if ((mode != RTAC_CVP) && (mode != RTAC_CVS)) {
|
|
pr_err("%s: Invalid Mode for APR, mode = %d\n",
|
|
__func__, mode);
|
|
goto done;
|
|
}
|
|
|
|
mutex_lock(&rtac_voice_apr_mutex);
|
|
if (rtac_voice_apr_data[mode].apr_handle == NULL) {
|
|
pr_err("%s: APR not initialized\n", __func__);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
if (opcode == VSS_ICOMMON_CMD_SET_PARAM_V2) {
|
|
/* set payload size to in-band payload */
|
|
/* set data size to actual out of band payload size */
|
|
data_size = payload_size - 4 * sizeof(u32);
|
|
if (data_size > rtac_cal[VOICE_RTAC_CAL].map_data.map_size) {
|
|
pr_err("%s: Invalid data size = %d\n",
|
|
__func__, data_size);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
payload_size = 4 * sizeof(u32);
|
|
|
|
/* Copy buffer to out-of-band payload */
|
|
if (copy_from_user((void *)
|
|
rtac_cal[VOICE_RTAC_CAL].cal_data.kvaddr,
|
|
buf + 7 * sizeof(u32), data_size)) {
|
|
pr_err("%s: Could not copy payload from user buffer\n",
|
|
__func__);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
/* set payload size in packet */
|
|
rtac_voice_buffer[8] = data_size;
|
|
} else {
|
|
if (payload_size > MAX_PAYLOAD_SIZE) {
|
|
pr_err("%s: Invalid payload size = %d\n",
|
|
__func__, payload_size);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
/* Copy buffer to in-band payload */
|
|
if (copy_from_user(rtac_voice_buffer +
|
|
sizeof(voice_params)/sizeof(u32),
|
|
buf + 3 * sizeof(u32), payload_size)) {
|
|
pr_err("%s: Could not copy payload from user buffer\n",
|
|
__func__);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
/* Pack header */
|
|
voice_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
|
|
APR_HDR_LEN(20), APR_PKT_VER);
|
|
voice_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
|
|
payload_size);
|
|
voice_params.src_svc = 0;
|
|
voice_params.src_domain = APR_DOMAIN_APPS;
|
|
voice_params.src_port = get_voice_index(mode, dest_port);
|
|
voice_params.dest_svc = 0;
|
|
voice_params.dest_domain = APR_DOMAIN_MODEM;
|
|
voice_params.dest_port = (u16)dest_port;
|
|
voice_params.token = (opcode == VSS_ICOMMON_CMD_SET_PARAM_V2) ?
|
|
VOC_RTAC_SET_PARAM_TOKEN :
|
|
0;
|
|
voice_params.opcode = opcode;
|
|
|
|
/* fill for out-of-band */
|
|
rtac_voice_buffer[5] = rtac_cal[VOICE_RTAC_CAL].map_data.map_handle;
|
|
rtac_voice_buffer[6] =
|
|
lower_32_bits(rtac_cal[VOICE_RTAC_CAL].cal_data.paddr);
|
|
rtac_voice_buffer[7] =
|
|
msm_audio_populate_upper_32_bits(
|
|
rtac_cal[VOICE_RTAC_CAL].cal_data.paddr);
|
|
|
|
memcpy(rtac_voice_buffer, &voice_params, sizeof(voice_params));
|
|
atomic_set(&rtac_voice_apr_data[mode].cmd_state, 1);
|
|
|
|
pr_debug("%s: Sending RTAC command ioctl 0x%x, paddr 0x%pK\n",
|
|
__func__, opcode,
|
|
&rtac_cal[VOICE_RTAC_CAL].cal_data.paddr);
|
|
|
|
result = apr_send_pkt(rtac_voice_apr_data[mode].apr_handle,
|
|
(uint32_t *)rtac_voice_buffer);
|
|
if (result < 0) {
|
|
pr_err("%s: apr_send_pkt failed opcode = %x\n",
|
|
__func__, opcode);
|
|
goto err;
|
|
}
|
|
/* Wait for the callback */
|
|
result = wait_event_timeout(rtac_voice_apr_data[mode].cmd_wait,
|
|
(atomic_read(&rtac_voice_apr_data[mode].cmd_state) == 0),
|
|
msecs_to_jiffies(TIMEOUT_MS));
|
|
if (!result) {
|
|
pr_err("%s: apr_send_pkt timed out opcode = %x\n",
|
|
__func__, opcode);
|
|
goto err;
|
|
}
|
|
if (atomic_read(&rtac_common.apr_err_code)) {
|
|
pr_err("%s: DSP returned error code = [%s], opcode = 0x%x\n",
|
|
__func__, adsp_err_get_err_str(atomic_read(
|
|
&rtac_common.apr_err_code)),
|
|
opcode);
|
|
result = adsp_err_get_lnx_err_code(
|
|
atomic_read(
|
|
&rtac_common.apr_err_code));
|
|
goto err;
|
|
}
|
|
|
|
if (opcode == VSS_ICOMMON_CMD_GET_PARAM_V2) {
|
|
bytes_returned = ((u32 *)rtac_cal[VOICE_RTAC_CAL].cal_data.
|
|
kvaddr)[2] + 3 * sizeof(u32);
|
|
|
|
if (bytes_returned > rtac_cal[VOICE_RTAC_CAL].
|
|
map_data.map_size) {
|
|
pr_err("%s: Invalid data size = %d\n",
|
|
__func__, bytes_returned);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
if (bytes_returned > user_buf_size) {
|
|
pr_err("%s: User buf not big enough, size = 0x%x, returned size = 0x%x\n",
|
|
__func__, user_buf_size, bytes_returned);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
if (copy_to_user(buf, (void *)
|
|
rtac_cal[VOICE_RTAC_CAL].cal_data.kvaddr,
|
|
bytes_returned)) {
|
|
pr_err("%s: Could not copy buffer to user, size = %d\n",
|
|
__func__, bytes_returned);
|
|
result = -EINVAL;
|
|
goto err;
|
|
}
|
|
} else {
|
|
bytes_returned = data_size;
|
|
}
|
|
mutex_unlock(&rtac_voice_apr_mutex);
|
|
done:
|
|
return bytes_returned;
|
|
err:
|
|
mutex_unlock(&rtac_voice_apr_mutex);
|
|
return result;
|
|
}
|
|
|
|
void get_rtac_adm_data(struct rtac_adm *adm_data)
|
|
{
|
|
mutex_lock(&rtac_adm_mutex);
|
|
memcpy(adm_data, &rtac_adm_data, sizeof(struct rtac_adm));
|
|
mutex_unlock(&rtac_adm_mutex);
|
|
}
|
|
|
|
|
|
static long rtac_ioctl_shared(struct file *f,
|
|
unsigned int cmd, void *arg)
|
|
{
|
|
int result = 0;
|
|
|
|
if (!arg) {
|
|
pr_err("%s: No data sent to driver!\n", __func__);
|
|
result = -EFAULT;
|
|
goto done;
|
|
}
|
|
|
|
switch (cmd) {
|
|
case AUDIO_GET_RTAC_ADM_INFO: {
|
|
mutex_lock(&rtac_adm_mutex);
|
|
if (copy_to_user((void *)arg, &rtac_adm_data,
|
|
sizeof(rtac_adm_data))) {
|
|
pr_err("%s: copy_to_user failed for AUDIO_GET_RTAC_ADM_INFO\n",
|
|
__func__);
|
|
mutex_unlock(&rtac_adm_mutex);
|
|
return -EFAULT;
|
|
}
|
|
result = sizeof(rtac_adm_data);
|
|
mutex_unlock(&rtac_adm_mutex);
|
|
break;
|
|
}
|
|
case AUDIO_GET_RTAC_VOICE_INFO: {
|
|
mutex_lock(&rtac_voice_mutex);
|
|
if (copy_to_user((void *)arg, &rtac_voice_data,
|
|
sizeof(rtac_voice_data))) {
|
|
pr_err("%s: copy_to_user failed for AUDIO_GET_RTAC_VOICE_INFO\n",
|
|
__func__);
|
|
mutex_unlock(&rtac_voice_mutex);
|
|
return -EFAULT;
|
|
}
|
|
result = sizeof(rtac_voice_data);
|
|
mutex_unlock(&rtac_voice_mutex);
|
|
break;
|
|
}
|
|
|
|
case AUDIO_GET_RTAC_ADM_CAL:
|
|
result = send_adm_apr((void *)arg, ADM_CMD_GET_PP_PARAMS_V5);
|
|
break;
|
|
case AUDIO_SET_RTAC_ADM_CAL:
|
|
result = send_adm_apr((void *)arg, ADM_CMD_SET_PP_PARAMS_V5);
|
|
break;
|
|
case AUDIO_GET_RTAC_ASM_CAL:
|
|
result = send_rtac_asm_apr((void *)arg,
|
|
ASM_STREAM_CMD_GET_PP_PARAMS_V2);
|
|
break;
|
|
case AUDIO_SET_RTAC_ASM_CAL:
|
|
result = send_rtac_asm_apr((void *)arg,
|
|
ASM_STREAM_CMD_SET_PP_PARAMS_V2);
|
|
break;
|
|
case AUDIO_GET_RTAC_CVS_CAL:
|
|
result = send_voice_apr(RTAC_CVS, (void *) arg,
|
|
VSS_ICOMMON_CMD_GET_PARAM_V2);
|
|
break;
|
|
case AUDIO_SET_RTAC_CVS_CAL:
|
|
result = send_voice_apr(RTAC_CVS, (void *) arg,
|
|
VSS_ICOMMON_CMD_SET_PARAM_V2);
|
|
break;
|
|
case AUDIO_GET_RTAC_CVP_CAL:
|
|
result = send_voice_apr(RTAC_CVP, (void *) arg,
|
|
VSS_ICOMMON_CMD_GET_PARAM_V2);
|
|
break;
|
|
case AUDIO_SET_RTAC_CVP_CAL:
|
|
result = send_voice_apr(RTAC_CVP, (void *) arg,
|
|
VSS_ICOMMON_CMD_SET_PARAM_V2);
|
|
break;
|
|
case AUDIO_GET_RTAC_AFE_CAL:
|
|
result = send_rtac_afe_apr((void *)arg,
|
|
AFE_PORT_CMD_GET_PARAM_V2);
|
|
break;
|
|
case AUDIO_SET_RTAC_AFE_CAL:
|
|
result = send_rtac_afe_apr((void *)arg,
|
|
AFE_PORT_CMD_SET_PARAM_V2);
|
|
break;
|
|
default:
|
|
pr_err("%s: Invalid IOCTL, command = %d!\n",
|
|
__func__, cmd);
|
|
result = -EINVAL;
|
|
}
|
|
done:
|
|
return result;
|
|
}
|
|
|
|
static long rtac_ioctl(struct file *f,
|
|
unsigned int cmd, unsigned long arg)
|
|
{
|
|
int result = 0;
|
|
|
|
if (!arg) {
|
|
pr_err("%s: No data sent to driver!\n", __func__);
|
|
result = -EFAULT;
|
|
} else {
|
|
result = rtac_ioctl_shared(f, cmd, (void __user *)arg);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
#define AUDIO_GET_RTAC_ADM_INFO_32 _IOR(CAL_IOCTL_MAGIC, 207, compat_uptr_t)
|
|
#define AUDIO_GET_RTAC_VOICE_INFO_32 _IOR(CAL_IOCTL_MAGIC, 208, compat_uptr_t)
|
|
#define AUDIO_GET_RTAC_ADM_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 209, compat_uptr_t)
|
|
#define AUDIO_SET_RTAC_ADM_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 210, compat_uptr_t)
|
|
#define AUDIO_GET_RTAC_ASM_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 211, compat_uptr_t)
|
|
#define AUDIO_SET_RTAC_ASM_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 212, compat_uptr_t)
|
|
#define AUDIO_GET_RTAC_CVS_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 213, compat_uptr_t)
|
|
#define AUDIO_SET_RTAC_CVS_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 214, compat_uptr_t)
|
|
#define AUDIO_GET_RTAC_CVP_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 215, compat_uptr_t)
|
|
#define AUDIO_SET_RTAC_CVP_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 216, compat_uptr_t)
|
|
#define AUDIO_GET_RTAC_AFE_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 217, compat_uptr_t)
|
|
#define AUDIO_SET_RTAC_AFE_CAL_32 _IOWR(CAL_IOCTL_MAGIC, 218, compat_uptr_t)
|
|
|
|
static long rtac_compat_ioctl(struct file *f,
|
|
unsigned int cmd, unsigned long arg)
|
|
{
|
|
int result = 0;
|
|
|
|
if (!arg) {
|
|
pr_err("%s: No data sent to driver!\n", __func__);
|
|
result = -EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
switch (cmd) {
|
|
case AUDIO_GET_RTAC_ADM_INFO_32:
|
|
cmd = AUDIO_GET_RTAC_ADM_INFO;
|
|
goto process;
|
|
case AUDIO_GET_RTAC_VOICE_INFO_32:
|
|
cmd = AUDIO_GET_RTAC_VOICE_INFO;
|
|
goto process;
|
|
case AUDIO_GET_RTAC_AFE_CAL_32:
|
|
cmd = AUDIO_GET_RTAC_AFE_CAL;
|
|
goto process;
|
|
case AUDIO_SET_RTAC_AFE_CAL_32:
|
|
cmd = AUDIO_SET_RTAC_AFE_CAL;
|
|
goto process;
|
|
case AUDIO_GET_RTAC_ADM_CAL_32:
|
|
cmd = AUDIO_GET_RTAC_ADM_CAL;
|
|
goto process;
|
|
case AUDIO_SET_RTAC_ADM_CAL_32:
|
|
cmd = AUDIO_SET_RTAC_ADM_CAL;
|
|
goto process;
|
|
case AUDIO_GET_RTAC_ASM_CAL_32:
|
|
cmd = AUDIO_GET_RTAC_ASM_CAL;
|
|
goto process;
|
|
case AUDIO_SET_RTAC_ASM_CAL_32:
|
|
cmd = AUDIO_SET_RTAC_ASM_CAL;
|
|
goto process;
|
|
case AUDIO_GET_RTAC_CVS_CAL_32:
|
|
cmd = AUDIO_GET_RTAC_CVS_CAL;
|
|
goto process;
|
|
case AUDIO_SET_RTAC_CVS_CAL_32:
|
|
cmd = AUDIO_SET_RTAC_CVS_CAL;
|
|
goto process;
|
|
case AUDIO_GET_RTAC_CVP_CAL_32:
|
|
cmd = AUDIO_GET_RTAC_CVP_CAL;
|
|
goto process;
|
|
case AUDIO_SET_RTAC_CVP_CAL_32:
|
|
cmd = AUDIO_SET_RTAC_CVP_CAL;
|
|
process:
|
|
result = rtac_ioctl_shared(f, cmd, compat_ptr(arg));
|
|
break;
|
|
default:
|
|
result = -EINVAL;
|
|
pr_err("%s: Invalid IOCTL, command = %d!\n",
|
|
__func__, cmd);
|
|
break;
|
|
}
|
|
done:
|
|
return result;
|
|
}
|
|
#else
|
|
#define rtac_compat_ioctl NULL
|
|
#endif
|
|
|
|
static const struct file_operations rtac_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = rtac_open,
|
|
.release = rtac_release,
|
|
.unlocked_ioctl = rtac_ioctl,
|
|
.compat_ioctl = rtac_compat_ioctl,
|
|
};
|
|
|
|
struct miscdevice rtac_misc = {
|
|
.minor = MISC_DYNAMIC_MINOR,
|
|
.name = "msm_rtac",
|
|
.fops = &rtac_fops,
|
|
};
|
|
|
|
int __init rtac_init(void)
|
|
{
|
|
int i = 0;
|
|
|
|
/* Driver */
|
|
atomic_set(&rtac_common.usage_count, 0);
|
|
atomic_set(&rtac_common.apr_err_code, 0);
|
|
|
|
/* ADM */
|
|
memset(&rtac_adm_data, 0, sizeof(rtac_adm_data));
|
|
rtac_adm_apr_data.apr_handle = NULL;
|
|
atomic_set(&rtac_adm_apr_data.cmd_state, 0);
|
|
init_waitqueue_head(&rtac_adm_apr_data.cmd_wait);
|
|
mutex_init(&rtac_adm_mutex);
|
|
mutex_init(&rtac_adm_apr_mutex);
|
|
|
|
rtac_adm_buffer = kzalloc(
|
|
rtac_cal[ADM_RTAC_CAL].map_data.map_size, GFP_KERNEL);
|
|
if (rtac_adm_buffer == NULL)
|
|
goto nomem;
|
|
|
|
/* ASM */
|
|
for (i = 0; i < ASM_ACTIVE_STREAMS_ALLOWED+1; i++) {
|
|
rtac_asm_apr_data[i].apr_handle = NULL;
|
|
atomic_set(&rtac_asm_apr_data[i].cmd_state, 0);
|
|
init_waitqueue_head(&rtac_asm_apr_data[i].cmd_wait);
|
|
}
|
|
mutex_init(&rtac_asm_apr_mutex);
|
|
|
|
rtac_asm_buffer = kzalloc(
|
|
rtac_cal[ASM_RTAC_CAL].map_data.map_size, GFP_KERNEL);
|
|
if (rtac_asm_buffer == NULL) {
|
|
kzfree(rtac_adm_buffer);
|
|
goto nomem;
|
|
}
|
|
|
|
/* AFE */
|
|
rtac_afe_apr_data.apr_handle = NULL;
|
|
atomic_set(&rtac_afe_apr_data.cmd_state, 0);
|
|
init_waitqueue_head(&rtac_afe_apr_data.cmd_wait);
|
|
mutex_init(&rtac_afe_apr_mutex);
|
|
|
|
rtac_afe_buffer = kzalloc(
|
|
rtac_cal[AFE_RTAC_CAL].map_data.map_size, GFP_KERNEL);
|
|
if (rtac_afe_buffer == NULL) {
|
|
kzfree(rtac_adm_buffer);
|
|
kzfree(rtac_asm_buffer);
|
|
goto nomem;
|
|
}
|
|
|
|
/* Voice */
|
|
memset(&rtac_voice_data, 0, sizeof(rtac_voice_data));
|
|
for (i = 0; i < RTAC_VOICE_MODES; i++) {
|
|
rtac_voice_apr_data[i].apr_handle = NULL;
|
|
atomic_set(&rtac_voice_apr_data[i].cmd_state, 0);
|
|
init_waitqueue_head(&rtac_voice_apr_data[i].cmd_wait);
|
|
}
|
|
mutex_init(&rtac_voice_mutex);
|
|
mutex_init(&rtac_voice_apr_mutex);
|
|
|
|
rtac_voice_buffer = kzalloc(
|
|
rtac_cal[VOICE_RTAC_CAL].map_data.map_size, GFP_KERNEL);
|
|
if (rtac_voice_buffer == NULL) {
|
|
kzfree(rtac_adm_buffer);
|
|
kzfree(rtac_asm_buffer);
|
|
kzfree(rtac_afe_buffer);
|
|
goto nomem;
|
|
}
|
|
|
|
return misc_register(&rtac_misc);
|
|
nomem:
|
|
return -ENOMEM;
|
|
}
|
|
|
|
void rtac_exit(void)
|
|
{
|
|
kzfree(rtac_adm_buffer);
|
|
kzfree(rtac_asm_buffer);
|
|
kzfree(rtac_afe_buffer);
|
|
misc_deregister(&rtac_misc);
|
|
}
|
|
|
|
MODULE_DESCRIPTION("SoC QDSP6v2 Real-Time Audio Calibration driver");
|
|
MODULE_LICENSE("GPL v2");
|