/* Copyright (c) 2013, 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "msm-dolby-dap-config.h" /* dolby endp based parameters */ struct dolby_dap_endp_params_s { int device; int device_ch_caps; int dap_device; int params_id[DOLBY_NUM_ENDP_DEPENDENT_PARAMS]; int params_len[DOLBY_NUM_ENDP_DEPENDENT_PARAMS]; int params_offset[DOLBY_NUM_ENDP_DEPENDENT_PARAMS]; int params_val[DOLBY_ENDDEP_PARAM_LENGTH]; }; const struct dolby_dap_endp_params_s dolby_dap_endp_params[NUM_DOLBY_ENDP_DEVICE] = { {EARPIECE, 2, DOLBY_ENDP_EXT_SPEAKERS, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {SPEAKER, 2, DOLBY_ENDP_INT_SPEAKERS, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {WIRED_HEADSET, 2, DOLBY_ENDP_HEADPHONES, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {WIRED_HEADPHONE, 2, DOLBY_ENDP_HEADPHONES, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {BLUETOOTH_SCO, 2, DOLBY_ENDP_EXT_SPEAKERS, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {BLUETOOTH_SCO_HEADSET, 2, DOLBY_ENDP_EXT_SPEAKERS, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {BLUETOOTH_SCO_CARKIT, 2, DOLBY_ENDP_EXT_SPEAKERS, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {BLUETOOTH_A2DP, 2, DOLBY_ENDP_EXT_SPEAKERS, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {BLUETOOTH_A2DP_HEADPHONES, 2, DOLBY_ENDP_HEADPHONES, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {BLUETOOTH_A2DP_SPEAKER, 2, DOLBY_ENDP_EXT_SPEAKERS, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {AUX_DIGITAL, 2, DOLBY_ENDP_HDMI, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} }, {AUX_DIGITAL, 6, DOLBY_ENDP_HDMI, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} }, {AUX_DIGITAL, 8, DOLBY_ENDP_HDMI, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} }, {ANLG_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {DGTL_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {USB_ACCESSORY, 2, DOLBY_ENDP_EXT_SPEAKERS, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {USB_DEVICE, 2, DOLBY_ENDP_EXT_SPEAKERS, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {REMOTE_SUBMIX, 2, DOLBY_ENDP_EXT_SPEAKERS, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {ANC_HEADSET, 2, DOLBY_ENDP_HEADPHONES, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {ANC_HEADPHONE, 2, DOLBY_ENDP_HEADPHONES, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {PROXY, 2, DOLBY_ENDP_EXT_SPEAKERS, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {FM, 2, DOLBY_ENDP_EXT_SPEAKERS, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, {FM_TX, 2, DOLBY_ENDP_EXT_SPEAKERS, {DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH}, {DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} }, }; /* dolby param ids to/from dsp */ static uint32_t dolby_dap_params_id[ALL_DOLBY_PARAMS] = { DOLBY_PARAM_ID_VDHE, DOLBY_PARAM_ID_VSPE, DOLBY_PARAM_ID_DSSF, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLE, DOLBY_PARAM_ID_DVMC, DOLBY_PARAM_ID_DVME, DOLBY_PARAM_ID_IENB, DOLBY_PARAM_ID_IEBF, DOLBY_PARAM_ID_IEON, DOLBY_PARAM_ID_DEON, DOLBY_PARAM_ID_NGON, DOLBY_PARAM_ID_GEON, DOLBY_PARAM_ID_GENB, DOLBY_PARAM_ID_GEBF, DOLBY_PARAM_ID_AONB, DOLBY_PARAM_ID_AOBF, DOLBY_PARAM_ID_AOBG, DOLBY_PARAM_ID_AOON, DOLBY_PARAM_ID_ARNB, DOLBY_PARAM_ID_ARBF, DOLBY_PARAM_ID_PLB, DOLBY_PARAM_ID_PLMD, DOLBY_PARAM_ID_DHSB, DOLBY_PARAM_ID_DHRG, DOLBY_PARAM_ID_DSSB, DOLBY_PARAM_ID_DSSA, DOLBY_PARAM_ID_DVLA, DOLBY_PARAM_ID_IEBT, DOLBY_PARAM_ID_IEA, DOLBY_PARAM_ID_DEA, DOLBY_PARAM_ID_DED, DOLBY_PARAM_ID_GEBG, DOLBY_PARAM_ID_AOCC, DOLBY_PARAM_ID_ARBI, DOLBY_PARAM_ID_ARBL, DOLBY_PARAM_ID_ARBH, DOLBY_PARAM_ID_AROD, DOLBY_PARAM_ID_ARTP, DOLBY_PARAM_ID_VMON, DOLBY_PARAM_ID_VMB, DOLBY_PARAM_ID_VCNB, DOLBY_PARAM_ID_VCBF, DOLBY_PARAM_ID_PREG, DOLBY_PARAM_ID_VEN, DOLBY_PARAM_ID_PSTG, DOLBY_COMMIT_ALL_TO_DSP, DOLBY_COMMIT_TO_DSP, DOLBY_USE_CACHE, DOLBY_AUTO_ENDP, DOLBY_AUTO_ENDDEP_PARAMS }; /* modifed state: 0x00000000 - Not updated * > 0x00000000 && < 0x00010000 * Updated and not commited to DSP * 0x00010001 - Updated and commited to DSP * > 0x00010001 - Modified the commited value */ static int dolby_dap_params_modified[MAX_DOLBY_PARAMS] = { 0 }; /* param offset */ static uint32_t dolby_dap_params_offset[MAX_DOLBY_PARAMS] = { DOLBY_PARAM_VDHE_OFFSET, DOLBY_PARAM_VSPE_OFFSET, DOLBY_PARAM_DSSF_OFFSET, DOLBY_PARAM_DVLI_OFFSET, DOLBY_PARAM_DVLO_OFFSET, DOLBY_PARAM_DVLE_OFFSET, DOLBY_PARAM_DVMC_OFFSET, DOLBY_PARAM_DVME_OFFSET, DOLBY_PARAM_IENB_OFFSET, DOLBY_PARAM_IEBF_OFFSET, DOLBY_PARAM_IEON_OFFSET, DOLBY_PARAM_DEON_OFFSET, DOLBY_PARAM_NGON_OFFSET, DOLBY_PARAM_GEON_OFFSET, DOLBY_PARAM_GENB_OFFSET, DOLBY_PARAM_GEBF_OFFSET, DOLBY_PARAM_AONB_OFFSET, DOLBY_PARAM_AOBF_OFFSET, DOLBY_PARAM_AOBG_OFFSET, DOLBY_PARAM_AOON_OFFSET, DOLBY_PARAM_ARNB_OFFSET, DOLBY_PARAM_ARBF_OFFSET, DOLBY_PARAM_PLB_OFFSET, DOLBY_PARAM_PLMD_OFFSET, DOLBY_PARAM_DHSB_OFFSET, DOLBY_PARAM_DHRG_OFFSET, DOLBY_PARAM_DSSB_OFFSET, DOLBY_PARAM_DSSA_OFFSET, DOLBY_PARAM_DVLA_OFFSET, DOLBY_PARAM_IEBT_OFFSET, DOLBY_PARAM_IEA_OFFSET, DOLBY_PARAM_DEA_OFFSET, DOLBY_PARAM_DED_OFFSET, DOLBY_PARAM_GEBG_OFFSET, DOLBY_PARAM_AOCC_OFFSET, DOLBY_PARAM_ARBI_OFFSET, DOLBY_PARAM_ARBL_OFFSET, DOLBY_PARAM_ARBH_OFFSET, DOLBY_PARAM_AROD_OFFSET, DOLBY_PARAM_ARTP_OFFSET, DOLBY_PARAM_VMON_OFFSET, DOLBY_PARAM_VMB_OFFSET, DOLBY_PARAM_VCNB_OFFSET, DOLBY_PARAM_VCBF_OFFSET, DOLBY_PARAM_PREG_OFFSET, DOLBY_PARAM_VEN_OFFSET, DOLBY_PARAM_PSTG_OFFSET }; /* param_length */ static uint32_t dolby_dap_params_length[MAX_DOLBY_PARAMS] = { DOLBY_PARAM_VDHE_LENGTH, DOLBY_PARAM_VSPE_LENGTH, DOLBY_PARAM_DSSF_LENGTH, DOLBY_PARAM_DVLI_LENGTH, DOLBY_PARAM_DVLO_LENGTH, DOLBY_PARAM_DVLE_LENGTH, DOLBY_PARAM_DVMC_LENGTH, DOLBY_PARAM_DVME_LENGTH, DOLBY_PARAM_IENB_LENGTH, DOLBY_PARAM_IEBF_LENGTH, DOLBY_PARAM_IEON_LENGTH, DOLBY_PARAM_DEON_LENGTH, DOLBY_PARAM_NGON_LENGTH, DOLBY_PARAM_GEON_LENGTH, DOLBY_PARAM_GENB_LENGTH, DOLBY_PARAM_GEBF_LENGTH, DOLBY_PARAM_AONB_LENGTH, DOLBY_PARAM_AOBF_LENGTH, DOLBY_PARAM_AOBG_LENGTH, DOLBY_PARAM_AOON_LENGTH, DOLBY_PARAM_ARNB_LENGTH, DOLBY_PARAM_ARBF_LENGTH, DOLBY_PARAM_PLB_LENGTH, DOLBY_PARAM_PLMD_LENGTH, DOLBY_PARAM_DHSB_LENGTH, DOLBY_PARAM_DHRG_LENGTH, DOLBY_PARAM_DSSB_LENGTH, DOLBY_PARAM_DSSA_LENGTH, DOLBY_PARAM_DVLA_LENGTH, DOLBY_PARAM_IEBT_LENGTH, DOLBY_PARAM_IEA_LENGTH, DOLBY_PARAM_DEA_LENGTH, DOLBY_PARAM_DED_LENGTH, DOLBY_PARAM_GEBG_LENGTH, DOLBY_PARAM_AOCC_LENGTH, DOLBY_PARAM_ARBI_LENGTH, DOLBY_PARAM_ARBL_LENGTH, DOLBY_PARAM_ARBH_LENGTH, DOLBY_PARAM_AROD_LENGTH, DOLBY_PARAM_ARTP_LENGTH, DOLBY_PARAM_VMON_LENGTH, DOLBY_PARAM_VMB_LENGTH, DOLBY_PARAM_VCNB_LENGTH, DOLBY_PARAM_VCBF_LENGTH, DOLBY_PARAM_PREG_LENGTH, DOLBY_PARAM_VEN_LENGTH, DOLBY_PARAM_PSTG_LENGTH }; /* param_value */ static uint32_t dolby_dap_params_value[TOTAL_LENGTH_DOLBY_PARAM] = {0}; struct dolby_dap_params_get_s { int32_t port_id; uint32_t device_id; uint32_t param_id; uint32_t offset; uint32_t length; }; struct dolby_dap_params_states_s { bool use_cache; bool auto_endp; bool enddep_params; int port_id; int port_open_count; int port_ids_dolby_can_be_enabled; int device; }; static struct dolby_dap_params_get_s dolby_dap_params_get = {-1, DEVICE_OUT_ALL, 0, 0, 0}; static struct dolby_dap_params_states_s dolby_dap_params_states = { true, true, true, DOLBY_INVALID_PORT_ID, 0, DEVICE_OUT_ALL, 0 }; /* port_ids_dolby_can_be_enabled is set to 0x7FFFFFFF. this needs to be removed after interface validation */ static int map_device_to_dolby_endpoint(int device) { int i, dolby_dap_device = DOLBY_ENDP_INT_SPEAKERS; for (i = 0; i < NUM_DOLBY_ENDP_DEVICE; i++) { if (dolby_dap_endp_params[i].device == device) { dolby_dap_device = dolby_dap_endp_params[i].dap_device; break; } } /* default the endpoint to speaker if corresponding device entry */ /* not found */ if (i >= NUM_DOLBY_ENDP_DEVICE) dolby_dap_params_states.device = SPEAKER; return dolby_dap_device; } static int dolby_dap_send_end_point(int port_id) { int rc = 0; char *params_value; int *update_params_value; uint32_t params_length = (DOLBY_PARAM_INT_ENDP_LENGTH + DOLBY_PARAM_PAYLOAD_SIZE) * sizeof(uint32_t); pr_debug("%s\n", __func__); params_value = kzalloc(params_length, GFP_KERNEL); if (!params_value) { pr_err("%s, params memory alloc failed", __func__); return -ENOMEM; } update_params_value = (int *)params_value; *update_params_value++ = DOLBY_BUNDLE_MODULE_ID; *update_params_value++ = DOLBY_PARAM_ID_INIT_ENDP; *update_params_value++ = DOLBY_PARAM_INT_ENDP_LENGTH * sizeof(uint32_t); *update_params_value++ = map_device_to_dolby_endpoint(dolby_dap_params_states.device); rc = adm_dolby_dap_send_params(port_id, params_value, params_length); if (rc) { pr_err("%s: send dolby params failed\n", __func__); rc = -EINVAL; } kfree(params_value); return rc; } static int dolby_dap_send_enddep_params(int port_id, int device_channels) { int i, j, rc = 0, idx, offset; char *params_value; int *update_params_value; uint32_t params_length = (DOLBY_ENDDEP_PARAM_LENGTH + DOLBY_NUM_ENDP_DEPENDENT_PARAMS * DOLBY_PARAM_PAYLOAD_SIZE) * sizeof(uint32_t); pr_debug("%s\n", __func__); params_value = kzalloc(params_length, GFP_KERNEL); if (!params_value) { pr_err("%s, params memory alloc failed", __func__); return -ENOMEM; } update_params_value = (int *)params_value; for (idx = 0; idx < NUM_DOLBY_ENDP_DEVICE; idx++) { if (dolby_dap_endp_params[idx].device == dolby_dap_params_states.device) { if (dolby_dap_params_states.device == AUX_DIGITAL) { if (dolby_dap_endp_params[idx].device_ch_caps == device_channels) break; } else { break; } } } if (idx >= NUM_DOLBY_ENDP_DEVICE) { pr_err("%s: device is not set accordingly\n", __func__); kfree(params_value); return -EINVAL; } for (i = 0; i < DOLBY_ENDDEP_PARAM_LENGTH; i++) { *update_params_value++ = DOLBY_BUNDLE_MODULE_ID; *update_params_value++ = dolby_dap_endp_params[idx].params_id[i]; *update_params_value++ = dolby_dap_endp_params[idx].params_len[i] * sizeof(uint32_t); offset = dolby_dap_endp_params[idx].params_offset[i]; for (j = 0; j < dolby_dap_endp_params[idx].params_len[i]; j++) *update_params_value++ = dolby_dap_endp_params[idx].params_val[offset+j]; } rc = adm_dolby_dap_send_params(port_id, params_value, params_length); if (rc) { pr_err("%s: send dolby params failed\n", __func__); rc = -EINVAL; } kfree(params_value); return rc; } static int dolby_dap_send_cached_params(int port_id, int commit) { char *params_value; int *update_params_value, rc = 0; uint32_t index_offset, i, j; uint32_t params_length = (TOTAL_LENGTH_DOLBY_PARAM + MAX_DOLBY_PARAMS * DOLBY_PARAM_PAYLOAD_SIZE) * sizeof(uint32_t); params_value = kzalloc(params_length, GFP_KERNEL); if (!params_value) { pr_err("%s, params memory alloc failed\n", __func__); return -ENOMEM; } update_params_value = (int *)params_value; params_length = 0; for (i = 0; i < MAX_DOLBY_PARAMS; i++) { if ((dolby_dap_params_modified[i] == 0) || ((commit) && ((dolby_dap_params_modified[i] & 0x00010000) && ((dolby_dap_params_modified[i] & 0x0000FFFF) <= 1)))) continue; *update_params_value++ = DOLBY_BUNDLE_MODULE_ID; *update_params_value++ = dolby_dap_params_id[i]; *update_params_value++ = dolby_dap_params_length[i] * sizeof(uint32_t); index_offset = dolby_dap_params_offset[i]; for (j = 0; j < dolby_dap_params_length[i]; j++) *update_params_value++ = dolby_dap_params_value[index_offset+j]; params_length += (DOLBY_PARAM_PAYLOAD_SIZE + dolby_dap_params_length[i]) * sizeof(uint32_t); } pr_debug("%s, valid param length: %d", __func__, params_length); if (params_length) { rc = adm_dolby_dap_send_params(port_id, params_value, params_length); if (rc) { pr_err("%s: send dolby params failed\n", __func__); kfree(params_value); return -EINVAL; } for (i = 0; i < MAX_DOLBY_PARAMS; i++) { if ((dolby_dap_params_modified[i] == 0) || ((commit) && ((dolby_dap_params_modified[i] & 0x00010000) && ((dolby_dap_params_modified[i] & 0x0000FFFF) <= 1)) )) continue; dolby_dap_params_modified[i] = 0x00010001; } } kfree(params_value); return 0; } int dolby_dap_init(int port_id, int channels) { int ret = 0; if ((port_id != DOLBY_INVALID_PORT_ID) && (port_id & dolby_dap_params_states.port_ids_dolby_can_be_enabled)) { dolby_dap_params_states.port_id = port_id; dolby_dap_params_states.port_open_count++; if (dolby_dap_params_states.auto_endp) { ret = dolby_dap_send_end_point(port_id); if (ret) { pr_err("%s: err sending endppoint\n", __func__); return ret; } } if (dolby_dap_params_states.use_cache) { ret = dolby_dap_send_cached_params(port_id, 0); if (ret) { pr_err("%s: err sending cached params\n", __func__); return ret; } } if (dolby_dap_params_states.enddep_params) { dolby_dap_send_enddep_params(port_id, channels); if (ret) { pr_err("%s: err sending endp dependent params\n", __func__); return ret; } } } return ret; } void dolby_dap_deinit(int port_id) { dolby_dap_params_states.port_open_count--; if ((dolby_dap_params_states.port_id == port_id) && (!dolby_dap_params_states.port_open_count)) dolby_dap_params_states.port_id = DOLBY_INVALID_PORT_ID; } static int map_device_to_port_id(int device) { int port_id = SLIMBUS_0_RX; device = DEVICE_OUT_ALL; /*update the device when single stream to multiple device is handled*/ if (device == DEVICE_OUT_ALL) { port_id = PRIMARY_I2S_RX | SLIMBUS_0_RX | HDMI_RX | INT_BT_SCO_RX | INT_FM_RX | RT_PROXY_PORT_001_RX | AFE_PORT_ID_PRIMARY_PCM_RX | MI2S_RX | SECONDARY_I2S_RX | SLIMBUS_1_RX | SLIMBUS_4_RX | SLIMBUS_3_RX | AFE_PORT_ID_SECONDARY_MI2S_RX; } else { /* update port_id based on the device */ } return port_id; } int msm_routing_get_dolby_dap_param_to_set_control( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* not used while setting the parameters */ return 0; } int msm_routing_put_dolby_dap_param_to_set_control( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int rc = 0; uint32_t idx, j; uint32_t device = ucontrol->value.integer.value[0]; uint32_t param_id = ucontrol->value.integer.value[1]; uint32_t offset = ucontrol->value.integer.value[2]; uint32_t length = ucontrol->value.integer.value[3]; int port_id = dolby_dap_params_states.port_id; dolby_dap_params_states.port_ids_dolby_can_be_enabled = map_device_to_port_id(device); for (idx = 0; idx < ALL_DOLBY_PARAMS; idx++) { /*paramid from user space*/ if (param_id == dolby_dap_params_id[idx]) break; } if (idx > ALL_DOLBY_PARAMS-1) { pr_err("%s: invalid param id 0x%x to set\n", __func__, param_id); return -EINVAL; } switch (idx) { case DOLBY_COMMIT_ALL_IDX: { /* COMIIT ALL: Send all parameters to DSP */ pr_debug("%s: COMMIT_ALL recvd\n", __func__); if (port_id != DOLBY_INVALID_PORT_ID) rc = dolby_dap_send_cached_params(port_id, 0); } break; case DOLBY_COMMIT_IDX: { pr_debug("%s: COMMIT recvd\n", __func__); /* COMMIT: Send only modified paramters to DSP */ if (port_id != DOLBY_INVALID_PORT_ID) rc = dolby_dap_send_cached_params(port_id, 1); } break; case DOLBY_USE_CACHE_IDX: { pr_debug("%s: USE CACHE recvd val: %ld\n", __func__, ucontrol->value.integer.value[4]); dolby_dap_params_states.use_cache = ucontrol->value.integer.value[4]; } break; case DOLBY_AUTO_ENDP_IDX: { pr_debug("%s: AUTO_ENDP recvd val: %ld\n", __func__, ucontrol->value.integer.value[4]); dolby_dap_params_states.auto_endp = ucontrol->value.integer.value[4]; } break; case DOLBY_AUTO_ENDDEP_IDX: { pr_debug("%s: USE_ENDDEP_PARAMS recvd val: %ld\n", __func__, ucontrol->value.integer.value[4]); dolby_dap_params_states.enddep_params = ucontrol->value.integer.value[4]; } break; default: { /* cache the parameters */ dolby_dap_params_modified[idx] += 1; dolby_dap_params_length[idx] = length; pr_debug("%s: param recvd deviceId=0x%x paramId=0x%x offset=%d length=%d\n", __func__, device, param_id, offset, length); for (j = 0; j < length; j++) { dolby_dap_params_value[ dolby_dap_params_offset[idx] + offset + j] = ucontrol->value.integer.value[4+j]; pr_debug("value[%d]: %ld\n", j, ucontrol->value.integer.value[4+j]); } } } return rc; } int msm_routing_get_dolby_dap_param_to_get_control( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int rc = 0, i; char *params_value; int *update_params_value; uint32_t params_length = DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM * sizeof(uint32_t); uint32_t param_payload_len = DOLBY_PARAM_PAYLOAD_SIZE * sizeof(uint32_t); int port_id = dolby_dap_params_states.port_id; if (port_id == DOLBY_INVALID_PORT_ID) { pr_err("%s, port_id not set, returning error", __func__); return -EINVAL; } params_value = kzalloc(params_length, GFP_KERNEL); if (!params_value) { pr_err("%s, params memory alloc failed\n", __func__); return -ENOMEM; } if (DOLBY_PARAM_ID_VER == dolby_dap_params_get.param_id) { rc = adm_dolby_dap_get_params(dolby_dap_params_get.port_id, DOLBY_BUNDLE_MODULE_ID, DOLBY_PARAM_ID_VER, params_length + param_payload_len, params_value); } else { for (i = 0; i < MAX_DOLBY_PARAMS; i++) if (dolby_dap_params_id[i] == dolby_dap_params_get.param_id) break; if (i > MAX_DOLBY_PARAMS-1) { pr_err("%s: invalid param id to set", __func__); rc = -EINVAL; } else { params_length = (dolby_dap_params_length[i] + DOLBY_PARAM_PAYLOAD_SIZE) * sizeof(uint32_t); rc = adm_dolby_dap_get_params( dolby_dap_params_get.port_id, DOLBY_BUNDLE_MODULE_ID, dolby_dap_params_id[i], params_length + param_payload_len, params_value); } } if (rc) { pr_err("%s: get parameters failed\n", __func__); kfree(params_value); return -EINVAL; } update_params_value = (int *)params_value; ucontrol->value.integer.value[0] = dolby_dap_params_get.device_id; ucontrol->value.integer.value[1] = dolby_dap_params_get.param_id; ucontrol->value.integer.value[2] = dolby_dap_params_get.offset; ucontrol->value.integer.value[3] = dolby_dap_params_get.length; pr_debug("%s: FROM DSP value[0] 0x%x value[1] %d value[2] 0x%x\n", __func__, update_params_value[0], update_params_value[1], update_params_value[2]); for (i = 0; i < dolby_dap_params_get.length; i++) { ucontrol->value.integer.value[DOLBY_PARAM_PAYLOAD_SIZE+i] = update_params_value[i]; pr_debug("value[%d]:%d\n", i, update_params_value[i]); } pr_debug("%s: Returning param_id=0x%x offset=%d length=%d\n", __func__, dolby_dap_params_get.param_id, dolby_dap_params_get.offset, dolby_dap_params_get.length); kfree(params_value); return 0; } int msm_routing_put_dolby_dap_param_to_get_control( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { dolby_dap_params_get.device_id = ucontrol->value.integer.value[0]; dolby_dap_params_get.port_id = (dolby_dap_params_get.device_id == DEVICE_OUT_ALL) ? dolby_dap_params_states.port_id : map_device_to_port_id(dolby_dap_params_get.device_id); dolby_dap_params_get.param_id = ucontrol->value.integer.value[1]; dolby_dap_params_get.offset = ucontrol->value.integer.value[2]; dolby_dap_params_get.length = ucontrol->value.integer.value[3]; pr_debug("%s: param_id=0x%x offset=%d length=%d\n", __func__, dolby_dap_params_get.param_id, dolby_dap_params_get.offset, dolby_dap_params_get.length); return 0; } int msm_routing_get_dolby_dap_param_visualizer_control( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { uint32_t length = dolby_dap_params_value[DOLBY_PARAM_VCNB_OFFSET]; char *visualizer_data; int i, rc; int *update_visualizer_data; uint32_t offset, params_length = (2*length + DOLBY_VIS_PARAM_HEADER_SIZE)*sizeof(uint32_t); uint32_t param_payload_len = DOLBY_PARAM_PAYLOAD_SIZE * sizeof(uint32_t); int port_id = dolby_dap_params_states.port_id; if (port_id == DOLBY_INVALID_PORT_ID) { pr_debug("%s, port_id not set, returning error", __func__); ucontrol->value.integer.value[0] = 0; return -EINVAL; } visualizer_data = kzalloc(params_length, GFP_KERNEL); if (!visualizer_data) { pr_err("%s, params memory alloc failed\n", __func__); return -ENOMEM; } offset = 0; params_length = length * sizeof(uint32_t); rc = adm_dolby_dap_get_params(dolby_dap_params_states.port_id, DOLBY_BUNDLE_MODULE_ID, DOLBY_PARAM_ID_VCBG, params_length + param_payload_len, visualizer_data + offset); if (rc) { pr_err("%s: get parameters failed\n", __func__); kfree(visualizer_data); return -EINVAL; } offset = length * sizeof(uint32_t); rc = adm_dolby_dap_get_params(dolby_dap_params_states.port_id, DOLBY_BUNDLE_MODULE_ID, DOLBY_PARAM_ID_VCBE, params_length + param_payload_len, visualizer_data + offset); if (rc) { pr_err("%s: get parameters failed\n", __func__); kfree(visualizer_data); return -EINVAL; } ucontrol->value.integer.value[0] = 2*length; pr_debug("%s: visualizer data length %ld\n", __func__, ucontrol->value.integer.value[0]); update_visualizer_data = (int *)visualizer_data; for (i = 0; i < 2*length; i++) { ucontrol->value.integer.value[1+i] = update_visualizer_data[i]; pr_debug("value[%d] %d\n", i, update_visualizer_data[i]); } kfree(visualizer_data); return 0; } int msm_routing_put_dolby_dap_param_visualizer_control( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* not used while getting the visualizer data */ return 0; } int msm_routing_get_dolby_dap_endpoint_control( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { /* not used while setting the endpoint */ return 0; } int msm_routing_put_dolby_dap_endpoint_control( struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int device = ucontrol->value.integer.value[0]; dolby_dap_params_states.device = device; return 0; }