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/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
new file mode 100644
index 0000000..7ce070c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -0,0 +1,905 @@
+/* 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/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/android_pmem.h>
+#include <linux/mm.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+
+
+#define MAX_NETWORKS 9
+#define NUM_ACTIVE_NETWORKS 6
+#define VOCPROC_STREAM_OFFSET NUM_ACTIVE_NETWORKS
+#define VOCPROC_VOL_OFFSET (NUM_ACTIVE_NETWORKS * 2)
+#define NUM_VOCPROC_CAL_TYPES (NUM_ACTIVE_NETWORKS * 3)
+#define NUM_AUDPROC_CAL_TYPES 3
+#define ACDB_BLOCK_SIZE 4096
+#define NUM_VOCPROC_BLOCKS 18
+
+enum {
+ RX_CAL,
+ TX_CAL,
+ MAX_AUDPROC_TYPES
+};
+
+struct acdb_data {
+ struct mutex acdb_mutex;
+
+ /* ANC Cal */
+ struct acdb_cal_block anc_cal;
+
+ /* AudProc Cal */
+ uint32_t adm_topology;
+ uint32_t asm_topology;
+ struct acdb_cal_block audproc_cal[MAX_AUDPROC_TYPES];
+ struct acdb_cal_block audstrm_cal[MAX_AUDPROC_TYPES];
+ struct acdb_cal_block audvol_cal[MAX_AUDPROC_TYPES];
+
+ /* VocProc Cal */
+ uint32_t voice_rx_topology;
+ uint32_t voice_tx_topology;
+ struct acdb_cal_block vocproc_cal[MAX_NETWORKS];
+ struct acdb_cal_block vocstrm_cal[MAX_NETWORKS];
+ struct acdb_cal_block vocvol_cal[MAX_NETWORKS];
+ /* size of cal block tables above*/
+ uint32_t vocproc_cal_size;
+ uint32_t vocstrm_cal_size;
+ uint32_t vocvol_cal_size;
+ /* Total size of cal data for all networks */
+ uint32_t vocproc_total_cal_size;
+ uint32_t vocstrm_total_cal_size;
+ uint32_t vocvol_total_cal_size;
+
+ /* Sidetone Cal */
+ struct sidetone_cal sidetone_cal;
+
+ /* PMEM information */
+ int pmem_fd;
+ unsigned long paddr;
+ unsigned long kvaddr;
+ unsigned long pmem_len;
+ struct file *file;
+
+};
+
+static struct acdb_data acdb_data;
+static atomic_t usage_count;
+
+uint32_t get_voice_rx_topology(void)
+{
+ return acdb_data.voice_rx_topology;
+}
+
+void store_voice_rx_topology(uint32_t topology)
+{
+ acdb_data.voice_rx_topology = topology;
+}
+
+uint32_t get_voice_tx_topology(void)
+{
+ return acdb_data.voice_tx_topology;
+}
+
+void store_voice_tx_topology(uint32_t topology)
+{
+ acdb_data.voice_tx_topology = topology;
+}
+
+uint32_t get_adm_topology(void)
+{
+ return acdb_data.adm_topology;
+}
+
+void store_adm_topology(uint32_t topology)
+{
+ acdb_data.adm_topology = topology;
+}
+
+uint32_t get_asm_topology(void)
+{
+ return acdb_data.asm_topology;
+}
+
+void store_asm_topology(uint32_t topology)
+{
+ acdb_data.asm_topology = topology;
+}
+
+void get_all_voice_cal(struct acdb_cal_block *cal_block)
+{
+ cal_block->cal_kvaddr = acdb_data.vocproc_cal[0].cal_kvaddr;
+ cal_block->cal_paddr = acdb_data.vocproc_cal[0].cal_paddr;
+ cal_block->cal_size = acdb_data.vocproc_total_cal_size +
+ acdb_data.vocstrm_total_cal_size +
+ acdb_data.vocvol_total_cal_size;
+}
+
+void get_all_cvp_cal(struct acdb_cal_block *cal_block)
+{
+ cal_block->cal_kvaddr = acdb_data.vocproc_cal[0].cal_kvaddr;
+ cal_block->cal_paddr = acdb_data.vocproc_cal[0].cal_paddr;
+ cal_block->cal_size = acdb_data.vocproc_total_cal_size +
+ acdb_data.vocvol_total_cal_size;
+}
+
+void get_all_vocproc_cal(struct acdb_cal_block *cal_block)
+{
+ cal_block->cal_kvaddr = acdb_data.vocproc_cal[0].cal_kvaddr;
+ cal_block->cal_paddr = acdb_data.vocproc_cal[0].cal_paddr;
+ cal_block->cal_size = acdb_data.vocproc_total_cal_size;
+}
+
+void get_all_vocstrm_cal(struct acdb_cal_block *cal_block)
+{
+ cal_block->cal_kvaddr = acdb_data.vocstrm_cal[0].cal_kvaddr;
+ cal_block->cal_paddr = acdb_data.vocstrm_cal[0].cal_paddr;
+ cal_block->cal_size = acdb_data.vocstrm_total_cal_size;
+}
+
+void get_all_vocvol_cal(struct acdb_cal_block *cal_block)
+{
+ cal_block->cal_kvaddr = acdb_data.vocvol_cal[0].cal_kvaddr;
+ cal_block->cal_paddr = acdb_data.vocvol_cal[0].cal_paddr;
+ cal_block->cal_size = acdb_data.vocvol_total_cal_size;
+}
+
+void get_anc_cal(struct acdb_cal_block *cal_block)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_block == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ cal_block->cal_kvaddr = acdb_data.anc_cal.cal_kvaddr;
+ cal_block->cal_paddr = acdb_data.anc_cal.cal_paddr;
+ cal_block->cal_size = acdb_data.anc_cal.cal_size;
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void store_anc_cal(struct cal_block *cal_block)
+{
+ pr_debug("%s,\n", __func__);
+
+ if (cal_block->cal_offset > acdb_data.pmem_len) {
+ pr_err("%s: offset %d is > pmem_len %ld\n",
+ __func__, cal_block->cal_offset,
+ acdb_data.pmem_len);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ acdb_data.anc_cal.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
+ acdb_data.anc_cal.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.anc_cal.cal_size =
+ cal_block->cal_size;
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void get_audproc_buffer_data(struct audproc_buffer_data *cal_buffers)
+{
+ int i;
+ pr_debug("%s\n", __func__);
+
+ if (cal_buffers == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ for (i = 0; i < NUM_AUDPROC_BUFFERS; i++) {
+ cal_buffers->phys_addr[i] = (uint32_t)
+ (acdb_data.paddr +
+ (NUM_VOCPROC_BLOCKS + i) * ACDB_BLOCK_SIZE);
+ cal_buffers->buf_size[i] = ACDB_BLOCK_SIZE;
+ }
+done:
+ return;
+}
+
+void store_audproc_cal(int32_t path, struct cal_block *cal_block)
+{
+ pr_debug("%s, path = %d\n", __func__, path);
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ if (cal_block->cal_offset > acdb_data.pmem_len) {
+ pr_err("%s: offset %d is > pmem_len %ld\n",
+ __func__, cal_block->cal_offset,
+ acdb_data.pmem_len);
+ goto done;
+ }
+ if (path >= MAX_AUDPROC_TYPES) {
+ pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+ __func__, path);
+ goto done;
+ }
+
+ acdb_data.audproc_cal[path].cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
+ acdb_data.audproc_cal[path].cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.audproc_cal[path].cal_size =
+ cal_block->cal_size;
+
+done:
+ mutex_unlock(&acdb_data.acdb_mutex);
+ return;
+}
+
+void get_audproc_cal(int32_t path, struct acdb_cal_block *cal_block)
+{
+ pr_debug("%s, path = %d\n", __func__, path);
+
+ if (cal_block == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+ if (path >= MAX_AUDPROC_TYPES) {
+ pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+ __func__, path);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ cal_block->cal_kvaddr = acdb_data.audproc_cal[path].cal_kvaddr;
+ cal_block->cal_paddr = acdb_data.audproc_cal[path].cal_paddr;
+ cal_block->cal_size = acdb_data.audproc_cal[path].cal_size;
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void store_audstrm_cal(int32_t path, struct cal_block *cal_block)
+{
+ pr_debug("%s, path = %d\n", __func__, path);
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ if (cal_block->cal_offset > acdb_data.pmem_len) {
+ pr_err("%s: offset %d is > pmem_len %ld\n",
+ __func__, cal_block->cal_offset,
+ acdb_data.pmem_len);
+ goto done;
+ }
+ if (path >= MAX_AUDPROC_TYPES) {
+ pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+ __func__, path);
+ goto done;
+ }
+
+ acdb_data.audstrm_cal[path].cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
+ acdb_data.audstrm_cal[path].cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.audstrm_cal[path].cal_size =
+ cal_block->cal_size;
+
+done:
+ mutex_unlock(&acdb_data.acdb_mutex);
+ return;
+}
+
+void get_audstrm_cal(int32_t path, struct acdb_cal_block *cal_block)
+{
+ pr_debug("%s, path = %d\n", __func__, path);
+
+ if (cal_block == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+ if (path >= MAX_AUDPROC_TYPES) {
+ pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+ __func__, path);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ cal_block->cal_kvaddr = acdb_data.audstrm_cal[path].cal_kvaddr;
+ cal_block->cal_paddr = acdb_data.audstrm_cal[path].cal_paddr;
+ cal_block->cal_size = acdb_data.audstrm_cal[path].cal_size;
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void store_audvol_cal(int32_t path, struct cal_block *cal_block)
+{
+ pr_debug("%s, path = %d\n", __func__, path);
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ if (cal_block->cal_offset > acdb_data.pmem_len) {
+ pr_err("%s: offset %d is > pmem_len %ld\n",
+ __func__, cal_block->cal_offset,
+ acdb_data.pmem_len);
+ goto done;
+ }
+ if (path >= MAX_AUDPROC_TYPES) {
+ pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+ __func__, path);
+ goto done;
+ }
+
+ acdb_data.audvol_cal[path].cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
+ acdb_data.audvol_cal[path].cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.audvol_cal[path].cal_size =
+ cal_block->cal_size;
+
+done:
+ mutex_unlock(&acdb_data.acdb_mutex);
+ return;
+}
+
+void get_audvol_cal(int32_t path, struct acdb_cal_block *cal_block)
+{
+ pr_debug("%s, path = %d\n", __func__, path);
+
+ if (cal_block == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+ if (path > MAX_AUDPROC_TYPES || path < 0) {
+ pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+ __func__, path);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ cal_block->cal_kvaddr = acdb_data.audvol_cal[path].cal_kvaddr;
+ cal_block->cal_paddr = acdb_data.audvol_cal[path].cal_paddr;
+ cal_block->cal_size = acdb_data.audvol_cal[path].cal_size;
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+
+void store_vocproc_cal(int32_t len, struct cal_block *cal_blocks)
+{
+ int i;
+ pr_debug("%s\n", __func__);
+
+ if (len > MAX_NETWORKS) {
+ pr_err("%s: Calibration sent for %d networks, only %d are "
+ "supported!\n", __func__, len, MAX_NETWORKS);
+ goto done;
+ }
+
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ acdb_data.vocproc_total_cal_size = 0;
+ for (i = 0; i < len; i++) {
+ if (cal_blocks[i].cal_offset > acdb_data.pmem_len) {
+ pr_err("%s: offset %d is > pmem_len %ld\n",
+ __func__, cal_blocks[i].cal_offset,
+ acdb_data.pmem_len);
+ acdb_data.vocproc_cal[i].cal_size = 0;
+ } else {
+ acdb_data.vocproc_total_cal_size +=
+ cal_blocks[i].cal_size;
+ acdb_data.vocproc_cal[i].cal_size =
+ cal_blocks[i].cal_size;
+ acdb_data.vocproc_cal[i].cal_paddr =
+ cal_blocks[i].cal_offset +
+ acdb_data.paddr;
+ acdb_data.vocproc_cal[i].cal_kvaddr =
+ cal_blocks[i].cal_offset +
+ acdb_data.kvaddr;
+ }
+ }
+ acdb_data.vocproc_cal_size = len;
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void get_vocproc_cal(struct acdb_cal_data *cal_data)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_data == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ cal_data->num_cal_blocks = acdb_data.vocproc_cal_size;
+ cal_data->cal_blocks = &acdb_data.vocproc_cal[0];
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void store_vocstrm_cal(int32_t len, struct cal_block *cal_blocks)
+{
+ int i;
+ pr_debug("%s\n", __func__);
+
+ if (len > MAX_NETWORKS) {
+ pr_err("%s: Calibration sent for %d networks, only %d are "
+ "supported!\n", __func__, len, MAX_NETWORKS);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ acdb_data.vocstrm_total_cal_size = 0;
+ for (i = 0; i < len; i++) {
+ if (cal_blocks[i].cal_offset > acdb_data.pmem_len) {
+ pr_err("%s: offset %d is > pmem_len %ld\n",
+ __func__, cal_blocks[i].cal_offset,
+ acdb_data.pmem_len);
+ acdb_data.vocstrm_cal[i].cal_size = 0;
+ } else {
+ acdb_data.vocstrm_total_cal_size +=
+ cal_blocks[i].cal_size;
+ acdb_data.vocstrm_cal[i].cal_size =
+ cal_blocks[i].cal_size;
+ acdb_data.vocstrm_cal[i].cal_paddr =
+ cal_blocks[i].cal_offset +
+ acdb_data.paddr;
+ acdb_data.vocstrm_cal[i].cal_kvaddr =
+ cal_blocks[i].cal_offset +
+ acdb_data.kvaddr;
+ }
+ }
+ acdb_data.vocstrm_cal_size = len;
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void get_vocstrm_cal(struct acdb_cal_data *cal_data)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_data == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ cal_data->num_cal_blocks = acdb_data.vocstrm_cal_size;
+ cal_data->cal_blocks = &acdb_data.vocstrm_cal[0];
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void store_vocvol_cal(int32_t len, struct cal_block *cal_blocks)
+{
+ int i;
+ pr_debug("%s\n", __func__);
+
+ if (len > MAX_NETWORKS) {
+ pr_err("%s: Calibration sent for %d networks, only %d are "
+ "supported!\n", __func__, len, MAX_NETWORKS);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ acdb_data.vocvol_total_cal_size = 0;
+ for (i = 0; i < len; i++) {
+ if (cal_blocks[i].cal_offset > acdb_data.pmem_len) {
+ pr_err("%s: offset %d is > pmem_len %ld\n",
+ __func__, cal_blocks[i].cal_offset,
+ acdb_data.pmem_len);
+ acdb_data.vocvol_cal[i].cal_size = 0;
+ } else {
+ acdb_data.vocvol_total_cal_size +=
+ cal_blocks[i].cal_size;
+ acdb_data.vocvol_cal[i].cal_size =
+ cal_blocks[i].cal_size;
+ acdb_data.vocvol_cal[i].cal_paddr =
+ cal_blocks[i].cal_offset +
+ acdb_data.paddr;
+ acdb_data.vocvol_cal[i].cal_kvaddr =
+ cal_blocks[i].cal_offset +
+ acdb_data.kvaddr;
+ }
+ }
+ acdb_data.vocvol_cal_size = len;
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void get_vocvol_cal(struct acdb_cal_data *cal_data)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_data == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ cal_data->num_cal_blocks = acdb_data.vocvol_cal_size;
+ cal_data->cal_blocks = &acdb_data.vocvol_cal[0];
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+void store_sidetone_cal(struct sidetone_cal *cal_data)
+{
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ acdb_data.sidetone_cal.enable = cal_data->enable;
+ acdb_data.sidetone_cal.gain = cal_data->gain;
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+}
+
+
+void get_sidetone_cal(struct sidetone_cal *cal_data)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_data == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ mutex_lock(&acdb_data.acdb_mutex);
+
+ cal_data->enable = acdb_data.sidetone_cal.enable;
+ cal_data->gain = acdb_data.sidetone_cal.gain;
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+done:
+ return;
+}
+
+static int acdb_open(struct inode *inode, struct file *f)
+{
+ s32 result = 0;
+ pr_info("%s\n", __func__);
+
+ mutex_lock(&acdb_data.acdb_mutex);
+ if (acdb_data.pmem_fd) {
+ pr_info("%s: ACDB opened but PMEM allocated, using existing PMEM!\n",
+ __func__);
+ }
+ mutex_unlock(&acdb_data.acdb_mutex);
+
+ atomic_inc(&usage_count);
+ return result;
+}
+
+static int deregister_pmem(void)
+{
+ int result;
+ struct audproc_buffer_data buffer;
+
+ get_audproc_buffer_data(&buffer);
+
+ result = adm_memory_unmap_regions(buffer.phys_addr,
+ buffer.buf_size, NUM_AUDPROC_BUFFERS);
+
+ if (result < 0)
+ pr_err("Audcal unmap did not work!\n");
+
+ if (acdb_data.pmem_fd) {
+ put_pmem_file(acdb_data.file);
+ acdb_data.pmem_fd = 0;
+ }
+ return result;
+}
+
+static int register_pmem(void)
+{
+ int result;
+ struct audproc_buffer_data buffer;
+
+ result = get_pmem_file(acdb_data.pmem_fd, &acdb_data.paddr,
+ &acdb_data.kvaddr, &acdb_data.pmem_len,
+ &acdb_data.file);
+ if (result != 0) {
+ acdb_data.pmem_fd = 0;
+ pr_err("%s: Could not register PMEM!!!\n", __func__);
+ goto done;
+ }
+
+ pr_debug("AUDIO_REGISTER_PMEM done! paddr = 0x%lx, "
+ "kvaddr = 0x%lx, len = x%lx\n", acdb_data.paddr,
+ acdb_data.kvaddr, acdb_data.pmem_len);
+ get_audproc_buffer_data(&buffer);
+ result = adm_memory_map_regions(buffer.phys_addr, 0,
+ buffer.buf_size,
+ NUM_AUDPROC_BUFFERS);
+ if (result < 0)
+ pr_err("Audcal mmap did not work!\n");
+ goto done;
+
+done:
+ return result;
+}
+static long acdb_ioctl(struct file *f,
+ unsigned int cmd, unsigned long arg)
+{
+ s32 result = 0;
+ s32 audproc_path;
+ s32 size;
+ u32 topology;
+ struct cal_block data[MAX_NETWORKS];
+ pr_debug("%s\n", __func__);
+
+ switch (cmd) {
+ case AUDIO_REGISTER_PMEM:
+ pr_debug("AUDIO_REGISTER_PMEM\n");
+ mutex_lock(&acdb_data.acdb_mutex);
+ if (acdb_data.pmem_fd) {
+ deregister_pmem();
+ pr_info("Remove the existing PMEM\n");
+ }
+
+ if (copy_from_user(&acdb_data.pmem_fd, (void *)arg,
+ sizeof(acdb_data.pmem_fd))) {
+ pr_err("%s: fail to copy pmem handle!\n", __func__);
+ result = -EFAULT;
+ } else {
+ result = register_pmem();
+ }
+ mutex_unlock(&acdb_data.acdb_mutex);
+ goto done;
+
+ case AUDIO_DEREGISTER_PMEM:
+ pr_debug("AUDIO_DEREGISTER_PMEM\n");
+ mutex_lock(&acdb_data.acdb_mutex);
+ deregister_pmem();
+ mutex_unlock(&acdb_data.acdb_mutex);
+ goto done;
+ case AUDIO_SET_VOICE_RX_TOPOLOGY:
+ if (copy_from_user(&topology, (void *)arg,
+ sizeof(topology))) {
+ pr_err("%s: fail to copy topology!\n", __func__);
+ result = -EFAULT;
+ }
+ store_voice_rx_topology(topology);
+ goto done;
+ case AUDIO_SET_VOICE_TX_TOPOLOGY:
+ if (copy_from_user(&topology, (void *)arg,
+ sizeof(topology))) {
+ pr_err("%s: fail to copy topology!\n", __func__);
+ result = -EFAULT;
+ }
+ store_voice_tx_topology(topology);
+ goto done;
+ case AUDIO_SET_ADM_TOPOLOGY:
+ if (copy_from_user(&topology, (void *)arg,
+ sizeof(topology))) {
+ pr_err("%s: fail to copy topology!\n", __func__);
+ result = -EFAULT;
+ }
+ store_adm_topology(topology);
+ goto done;
+ case AUDIO_SET_ASM_TOPOLOGY:
+ if (copy_from_user(&topology, (void *)arg,
+ sizeof(topology))) {
+ pr_err("%s: fail to copy topology!\n", __func__);
+ result = -EFAULT;
+ }
+ store_asm_topology(topology);
+ goto done;
+ }
+
+ if (copy_from_user(&size, (void *) arg, sizeof(size))) {
+
+ result = -EFAULT;
+ goto done;
+ }
+
+ if (size <= 0) {
+ pr_err("%s: Invalid size sent to driver: %d\n",
+ __func__, size);
+ result = -EFAULT;
+ goto done;
+ }
+
+ if (copy_from_user(data, (void *)(arg + sizeof(size)), size)) {
+
+ pr_err("%s: fail to copy table size %d\n", __func__, size);
+ result = -EFAULT;
+ goto done;
+ }
+
+ if (data == NULL) {
+ pr_err("%s: NULL pointer sent to driver!\n", __func__);
+ result = -EFAULT;
+ goto done;
+ }
+
+ switch (cmd) {
+ case AUDIO_SET_AUDPROC_TX_CAL:
+ audproc_path = TX_CAL;
+ if (size > sizeof(struct cal_block))
+ pr_err("%s: More Audproc Cal then expected, "
+ "size received: %d\n", __func__, size);
+ store_audproc_cal(audproc_path, data);
+ break;
+ case AUDIO_SET_AUDPROC_RX_CAL:
+ audproc_path = RX_CAL;
+ if (size > sizeof(struct cal_block))
+ pr_err("%s: More Audproc Cal then expected, "
+ "size received: %d\n", __func__, size);
+ store_audproc_cal(audproc_path, data);
+ break;
+ case AUDIO_SET_AUDPROC_TX_STREAM_CAL:
+ audproc_path = TX_CAL;
+ if (size > sizeof(struct cal_block))
+ pr_err("%s: More Audproc Cal then expected, "
+ "size received: %d\n", __func__, size);
+ store_audstrm_cal(audproc_path, data);
+ break;
+ case AUDIO_SET_AUDPROC_RX_STREAM_CAL:
+ audproc_path = RX_CAL;
+ if (size > sizeof(struct cal_block))
+ pr_err("%s: More Audproc Cal then expected, "
+ "size received: %d\n", __func__, size);
+ store_audstrm_cal(audproc_path, data);
+ break;
+ case AUDIO_SET_AUDPROC_TX_VOL_CAL:
+ audproc_path = TX_CAL;
+ if (size > sizeof(struct cal_block))
+ pr_err("%s: More Audproc Cal then expected, "
+ "size received: %d\n", __func__, size);
+ store_audvol_cal(audproc_path, data);
+ case AUDIO_SET_AUDPROC_RX_VOL_CAL:
+ audproc_path = RX_CAL;
+ if (size > sizeof(struct cal_block))
+ pr_err("%s: More Audproc Cal then expected, "
+ "size received: %d\n", __func__, size);
+ store_audvol_cal(audproc_path, data);
+ break;
+ case AUDIO_SET_VOCPROC_CAL:
+ store_vocproc_cal(size / sizeof(struct cal_block), data);
+ break;
+ case AUDIO_SET_VOCPROC_STREAM_CAL:
+ store_vocstrm_cal(size / sizeof(struct cal_block), data);
+ break;
+ case AUDIO_SET_VOCPROC_VOL_CAL:
+ store_vocvol_cal(size / sizeof(struct cal_block), data);
+ break;
+ case AUDIO_SET_SIDETONE_CAL:
+ if (size > sizeof(struct sidetone_cal))
+ pr_err("%s: More sidetone cal then expected, "
+ "size received: %d\n", __func__, size);
+ store_sidetone_cal((struct sidetone_cal *)data);
+ break;
+ case AUDIO_SET_ANC_CAL:
+ store_anc_cal(data);
+ break;
+ default:
+ pr_err("ACDB=> ACDB ioctl not found!\n");
+ }
+
+done:
+ return result;
+}
+
+static int acdb_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ int result = 0;
+ int size = vma->vm_end - vma->vm_start;
+
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&acdb_data.acdb_mutex);
+ if (acdb_data.pmem_fd) {
+ if (size <= acdb_data.pmem_len) {
+ vma->vm_page_prot = pgprot_noncached(
+ vma->vm_page_prot);
+ result = remap_pfn_range(vma,
+ vma->vm_start,
+ acdb_data.paddr >> PAGE_SHIFT,
+ size,
+ vma->vm_page_prot);
+ } else {
+ pr_err("%s: Not enough PMEM memory!\n", __func__);
+ result = -ENOMEM;
+ }
+ } else {
+ pr_err("%s: PMEM is not allocated, yet!\n", __func__);
+ result = -ENODEV;
+ }
+ mutex_unlock(&acdb_data.acdb_mutex);
+
+ return result;
+}
+
+static int acdb_release(struct inode *inode, struct file *f)
+{
+ s32 result = 0;
+
+ atomic_dec(&usage_count);
+ atomic_read(&usage_count);
+
+ pr_info("%s: ref count %d!\n", __func__,
+ atomic_read(&usage_count));
+
+ if (atomic_read(&usage_count) >= 1) {
+ result = -EBUSY;
+ } else {
+ mutex_lock(&acdb_data.acdb_mutex);
+ result = deregister_pmem();
+ mutex_unlock(&acdb_data.acdb_mutex);
+ }
+
+ return result;
+}
+
+static const struct file_operations acdb_fops = {
+ .owner = THIS_MODULE,
+ .open = acdb_open,
+ .release = acdb_release,
+ .unlocked_ioctl = acdb_ioctl,
+ .mmap = acdb_mmap,
+};
+
+struct miscdevice acdb_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_acdb",
+ .fops = &acdb_fops,
+};
+
+static int __init acdb_init(void)
+{
+ memset(&acdb_data, 0, sizeof(acdb_data));
+ mutex_init(&acdb_data.acdb_mutex);
+ atomic_set(&usage_count, 0);
+ return misc_register(&acdb_misc);
+}
+
+static void __exit acdb_exit(void)
+{
+}
+
+module_init(acdb_init);
+module_exit(acdb_exit);
+
+MODULE_DESCRIPTION("MSM 8x60 Audio ACDB driver");
+MODULE_LICENSE("GPL v2");