// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include #include #include #include #include #include struct mutex cal_lock; static int unmap_memory(struct cal_type_data *cal_type, struct cal_block_data *cal_block); size_t get_cal_info_size(int32_t cal_type) { size_t size = 0; size_t size1 = 0, size2 = 0; switch (cal_type) { case CVP_VOC_RX_TOPOLOGY_CAL_TYPE: size = sizeof(struct audio_cal_info_voc_top); break; case CVP_VOC_TX_TOPOLOGY_CAL_TYPE: size = sizeof(struct audio_cal_info_voc_top); break; case CVP_VOCPROC_STATIC_CAL_TYPE: size = sizeof(struct audio_cal_info_vocproc); break; case CVP_VOCPROC_DYNAMIC_CAL_TYPE: size = sizeof(struct audio_cal_info_vocvol); break; case CVS_VOCSTRM_STATIC_CAL_TYPE: size = 0; break; case CVP_VOCDEV_CFG_CAL_TYPE: size = sizeof(struct audio_cal_info_vocdev_cfg); break; case CVP_VOCPROC_STATIC_COL_CAL_TYPE: size = sizeof(struct audio_cal_info_voc_col); break; case CVP_VOCPROC_DYNAMIC_COL_CAL_TYPE: size = sizeof(struct audio_cal_info_voc_col); break; case CVS_VOCSTRM_STATIC_COL_CAL_TYPE: size = sizeof(struct audio_cal_info_voc_col); break; case ADM_TOPOLOGY_CAL_TYPE: case ADM_LSM_TOPOLOGY_CAL_TYPE: size = sizeof(struct audio_cal_info_adm_top); break; case ADM_CUST_TOPOLOGY_CAL_TYPE: case CORE_CUSTOM_TOPOLOGIES_CAL_TYPE: size = 0; break; case ADM_AUDPROC_CAL_TYPE: case ADM_LSM_AUDPROC_CAL_TYPE: case ADM_LSM_AUDPROC_PERSISTENT_CAL_TYPE: case ADM_AUDPROC_PERSISTENT_CAL_TYPE: size = sizeof(struct audio_cal_info_audproc); break; case ADM_AUDVOL_CAL_TYPE: case ADM_RTAC_AUDVOL_CAL_TYPE: size = sizeof(struct audio_cal_info_audvol); break; case ASM_TOPOLOGY_CAL_TYPE: size = sizeof(struct audio_cal_info_asm_top); break; case ASM_CUST_TOPOLOGY_CAL_TYPE: size = 0; break; case ASM_AUDSTRM_CAL_TYPE: size = sizeof(struct audio_cal_info_audstrm); break; case AFE_TOPOLOGY_CAL_TYPE: case AFE_LSM_TOPOLOGY_CAL_TYPE: size = sizeof(struct audio_cal_info_afe_top); break; case AFE_CUST_TOPOLOGY_CAL_TYPE: size = 0; break; case AFE_COMMON_RX_CAL_TYPE: size = sizeof(struct audio_cal_info_afe); break; case AFE_COMMON_TX_CAL_TYPE: case AFE_LSM_TX_CAL_TYPE: size = sizeof(struct audio_cal_info_afe); break; case AFE_FB_SPKR_PROT_CAL_TYPE: size = sizeof(struct audio_cal_info_spk_prot_cfg); break; case AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE: /* * Since get and set parameter structures are different in size * use the maximum size of get and set parameter structure */ size1 = max(sizeof(struct audio_cal_info_sp_th_vi_ftm_cfg), sizeof(struct audio_cal_info_sp_th_vi_param)); size2 = max(sizeof(struct audio_cal_info_sp_th_vi_v_vali_cfg), sizeof(struct audio_cal_info_sp_th_vi_v_vali_param)); size = max(size1, size2); break; case AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE: /* * Since get and set parameter structures are different in size * use the maximum size of get and set parameter structure */ size = max(sizeof(struct audio_cal_info_sp_ex_vi_ftm_cfg), sizeof(struct audio_cal_info_sp_ex_vi_param)); break; case AFE_FB_SPKR_PROT_V4_EX_VI_CAL_TYPE: size = sizeof(struct audio_cal_info_sp_v4_ex_vi_param); break; case AFE_ANC_CAL_TYPE: size = 0; break; case AFE_AANC_CAL_TYPE: size = sizeof(struct audio_cal_info_aanc); break; case AFE_HW_DELAY_CAL_TYPE: size = sizeof(struct audio_cal_info_hw_delay); break; case AFE_SIDETONE_CAL_TYPE: size = sizeof(struct audio_cal_info_sidetone); break; case AFE_SIDETONE_IIR_CAL_TYPE: size = sizeof(struct audio_cal_info_sidetone_iir); break; case LSM_CUST_TOPOLOGY_CAL_TYPE: size = 0; break; case LSM_TOPOLOGY_CAL_TYPE: size = sizeof(struct audio_cal_info_lsm_top); break; case ULP_LSM_TOPOLOGY_ID_CAL_TYPE: size = sizeof(struct audio_cal_info_lsm_top); break; case LSM_CAL_TYPE: size = sizeof(struct audio_cal_info_lsm); break; case ADM_RTAC_INFO_CAL_TYPE: size = 0; break; case VOICE_RTAC_INFO_CAL_TYPE: size = 0; break; case ADM_RTAC_APR_CAL_TYPE: size = 0; break; case ASM_RTAC_APR_CAL_TYPE: size = 0; break; case VOICE_RTAC_APR_CAL_TYPE: size = 0; break; case MAD_CAL_TYPE: size = 0; break; case ULP_AFE_CAL_TYPE: size = sizeof(struct audio_cal_info_afe); break; case ULP_LSM_CAL_TYPE: size = sizeof(struct audio_cal_info_lsm); break; case AUDIO_CORE_METAINFO_CAL_TYPE: size = sizeof(struct audio_cal_info_metainfo); break; case SRS_TRUMEDIA_CAL_TYPE: size = 0; break; default: pr_err("%s:Invalid cal type %d!", __func__, cal_type); } return size; } size_t get_user_cal_type_size(int32_t cal_type) { size_t size = 0; switch (cal_type) { case CVP_VOC_RX_TOPOLOGY_CAL_TYPE: size = sizeof(struct audio_cal_type_voc_top); break; case CVP_VOC_TX_TOPOLOGY_CAL_TYPE: size = sizeof(struct audio_cal_type_voc_top); break; case CVP_VOCPROC_STATIC_CAL_TYPE: size = sizeof(struct audio_cal_type_vocproc); break; case CVP_VOCPROC_DYNAMIC_CAL_TYPE: size = sizeof(struct audio_cal_type_vocvol); break; case CVS_VOCSTRM_STATIC_CAL_TYPE: size = sizeof(struct audio_cal_type_basic); break; case CVP_VOCDEV_CFG_CAL_TYPE: size = sizeof(struct audio_cal_type_vocdev_cfg); break; case CVP_VOCPROC_STATIC_COL_CAL_TYPE: case CVP_VOCPROC_DYNAMIC_COL_CAL_TYPE: case CVS_VOCSTRM_STATIC_COL_CAL_TYPE: size = sizeof(struct audio_cal_type_voc_col); break; case ADM_TOPOLOGY_CAL_TYPE: case ADM_LSM_TOPOLOGY_CAL_TYPE: size = sizeof(struct audio_cal_type_adm_top); break; case ADM_CUST_TOPOLOGY_CAL_TYPE: case CORE_CUSTOM_TOPOLOGIES_CAL_TYPE: size = sizeof(struct audio_cal_type_basic); break; case ADM_AUDPROC_CAL_TYPE: case ADM_LSM_AUDPROC_CAL_TYPE: case ADM_LSM_AUDPROC_PERSISTENT_CAL_TYPE: case ADM_AUDPROC_PERSISTENT_CAL_TYPE: size = sizeof(struct audio_cal_type_audproc); break; case ADM_AUDVOL_CAL_TYPE: case ADM_RTAC_AUDVOL_CAL_TYPE: size = sizeof(struct audio_cal_type_audvol); break; case ASM_TOPOLOGY_CAL_TYPE: size = sizeof(struct audio_cal_type_asm_top); break; case ASM_CUST_TOPOLOGY_CAL_TYPE: size = sizeof(struct audio_cal_type_basic); break; case ASM_AUDSTRM_CAL_TYPE: size = sizeof(struct audio_cal_type_audstrm); break; case AFE_TOPOLOGY_CAL_TYPE: case AFE_LSM_TOPOLOGY_CAL_TYPE: size = sizeof(struct audio_cal_type_afe_top); break; case AFE_CUST_TOPOLOGY_CAL_TYPE: size = sizeof(struct audio_cal_type_basic); break; case AFE_COMMON_RX_CAL_TYPE: size = sizeof(struct audio_cal_type_afe); break; case AFE_COMMON_TX_CAL_TYPE: case AFE_LSM_TX_CAL_TYPE: size = sizeof(struct audio_cal_type_afe); break; case AFE_FB_SPKR_PROT_CAL_TYPE: size = sizeof(struct audio_cal_type_fb_spk_prot_cfg); break; case AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE: /* * Since get and set parameter structures are different in size * use the maximum size of get and set parameter structure */ size = max(sizeof(struct audio_cal_type_sp_th_vi_ftm_cfg), sizeof(struct audio_cal_type_sp_th_vi_param)); break; case AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE: /* * Since get and set parameter structures are different in size * use the maximum size of get and set parameter structure */ size = max(sizeof(struct audio_cal_type_sp_ex_vi_ftm_cfg), sizeof(struct audio_cal_type_sp_ex_vi_param)); break; case AFE_FB_SPKR_PROT_V4_EX_VI_CAL_TYPE: size = sizeof(struct audio_cal_type_sp_v4_ex_vi_param); break; case AFE_ANC_CAL_TYPE: size = 0; break; case AFE_AANC_CAL_TYPE: size = sizeof(struct audio_cal_type_aanc); break; case AFE_HW_DELAY_CAL_TYPE: size = sizeof(struct audio_cal_type_hw_delay); break; case AFE_SIDETONE_CAL_TYPE: size = sizeof(struct audio_cal_type_sidetone); break; case AFE_SIDETONE_IIR_CAL_TYPE: size = sizeof(struct audio_cal_type_sidetone_iir); break; case LSM_CUST_TOPOLOGY_CAL_TYPE: size = sizeof(struct audio_cal_type_basic); break; case LSM_TOPOLOGY_CAL_TYPE: size = sizeof(struct audio_cal_type_lsm_top); break; case ULP_LSM_TOPOLOGY_ID_CAL_TYPE: size = sizeof(struct audio_cal_type_lsm_top); break; case LSM_CAL_TYPE: size = sizeof(struct audio_cal_type_lsm); break; case ADM_RTAC_INFO_CAL_TYPE: size = 0; break; case VOICE_RTAC_INFO_CAL_TYPE: size = 0; break; case ADM_RTAC_APR_CAL_TYPE: size = 0; break; case ASM_RTAC_APR_CAL_TYPE: size = 0; break; case VOICE_RTAC_APR_CAL_TYPE: size = 0; break; case MAD_CAL_TYPE: size = 0; break; case ULP_AFE_CAL_TYPE: size = sizeof(struct audio_cal_type_afe); break; case ULP_LSM_CAL_TYPE: size = sizeof(struct audio_cal_type_lsm); break; case AUDIO_CORE_METAINFO_CAL_TYPE: size = sizeof(struct audio_cal_type_metainfo); break; case SRS_TRUMEDIA_CAL_TYPE: size = 0; break; default: pr_err("%s:Invalid cal type %d!", __func__, cal_type); } return size; } int32_t cal_utils_get_cal_type_version(void *cal_type_data) { struct audio_cal_type_basic *data = NULL; data = (struct audio_cal_type_basic *)cal_type_data; return data->cal_hdr.version; } static struct cal_type_data *create_cal_type_data( struct cal_type_info *info) { struct cal_type_data *cal_type = NULL; if ((info->reg.cal_type < 0) || (info->reg.cal_type >= MAX_CAL_TYPES)) { pr_err("%s: cal type %d is Invalid!\n", __func__, info->reg.cal_type); goto done; } if (info->cal_util_callbacks.match_block == NULL) { pr_err("%s: cal type %d no method to match blocks!\n", __func__, info->reg.cal_type); goto done; } cal_type = kmalloc(sizeof(*cal_type), GFP_KERNEL); if (cal_type == NULL) goto done; INIT_LIST_HEAD(&cal_type->cal_blocks); mutex_init(&cal_type->lock); memcpy(&cal_type->info, info, sizeof(cal_type->info)); done: return cal_type; } /** * cal_utils_create_cal_types * * @num_cal_types: number of types * @cal_type: pointer to the cal types pointer * @info: pointer to info * * Returns 0 on success, EINVAL otherwise */ int cal_utils_create_cal_types(int num_cal_types, struct cal_type_data **cal_type, struct cal_type_info *info) { int ret = 0; int i; pr_debug("%s\n", __func__); if (cal_type == NULL) { pr_err("%s: cal_type is NULL!\n", __func__); ret = -EINVAL; goto done; } else if (info == NULL) { pr_err("%s: info is NULL!\n", __func__); ret = -EINVAL; goto done; } else if ((num_cal_types <= 0) || (num_cal_types > MAX_CAL_TYPES)) { pr_err("%s: num_cal_types of %d is Invalid!\n", __func__, num_cal_types); ret = -EINVAL; goto done; } for (i = 0; i < num_cal_types; i++) { if ((info[i].reg.cal_type < 0) || (info[i].reg.cal_type >= MAX_CAL_TYPES)) { pr_err("%s: cal type %d at index %d is Invalid!\n", __func__, info[i].reg.cal_type, i); ret = -EINVAL; goto done; } cal_type[i] = create_cal_type_data(&info[i]); if (cal_type[i] == NULL) { pr_err("%s: Could not allocate cal_type of index %d!\n", __func__, i); ret = -EINVAL; goto done; } ret = audio_cal_register(1, &info[i].reg); if (ret < 0) { pr_err("%s: audio_cal_register failed, ret = %d!\n", __func__, ret); ret = -EINVAL; goto done; } pr_debug("%s: cal type %d at index %d!\n", __func__, info[i].reg.cal_type, i); } done: return ret; } EXPORT_SYMBOL(cal_utils_create_cal_types); static void delete_cal_block(struct cal_block_data *cal_block) { pr_debug("%s\n", __func__); if (cal_block == NULL) goto done; list_del(&cal_block->list); kfree(cal_block->client_info); cal_block->client_info = NULL; kfree(cal_block->cal_info); cal_block->cal_info = NULL; if (cal_block->map_data.dma_buf != NULL) { if (cal_block->cma_mem) msm_audio_ion_free_cma(cal_block->map_data.dma_buf); else msm_audio_ion_free(cal_block->map_data.dma_buf); cal_block->map_data.dma_buf = NULL; } kfree(cal_block); cal_block = NULL; done: return; } static void destroy_all_cal_blocks(struct cal_type_data *cal_type) { int ret = 0; struct list_head *ptr, *next; struct cal_block_data *cal_block; list_for_each_safe(ptr, next, &cal_type->cal_blocks) { cal_block = list_entry(ptr, struct cal_block_data, list); ret = unmap_memory(cal_type, cal_block); if (ret < 0) { pr_err("%s: unmap_memory failed, cal type %d, ret = %d!\n", __func__, cal_type->info.reg.cal_type, ret); } delete_cal_block(cal_block); cal_block = NULL; } } static void destroy_cal_type_data(struct cal_type_data *cal_type) { if (cal_type == NULL) goto done; destroy_all_cal_blocks(cal_type); list_del(&cal_type->cal_blocks); kfree(cal_type); done: return; } /** * cal_utils_destroy_cal_types - * Destroys cal types and deregister from cal info * * @num_cal_types: number of cal types * @cal_type: cal type pointer with cal info * */ void cal_utils_destroy_cal_types(int num_cal_types, struct cal_type_data **cal_type) { int i; pr_debug("%s\n", __func__); if (cal_type == NULL) { pr_err("%s: cal_type is NULL!\n", __func__); goto done; } else if ((num_cal_types <= 0) || (num_cal_types > MAX_CAL_TYPES)) { pr_err("%s: num_cal_types of %d is Invalid!\n", __func__, num_cal_types); goto done; } for (i = 0; i < num_cal_types; i++) { audio_cal_deregister(1, &cal_type[i]->info.reg); destroy_cal_type_data(cal_type[i]); cal_type[i] = NULL; } done: return; } EXPORT_SYMBOL(cal_utils_destroy_cal_types); /** * cal_utils_get_only_cal_block * * @cal_type: pointer to the cal type * * Returns cal_block structure */ struct cal_block_data *cal_utils_get_only_cal_block( struct cal_type_data *cal_type) { struct list_head *ptr, *next; struct cal_block_data *cal_block = NULL; if (cal_type == NULL) goto done; list_for_each_safe(ptr, next, &cal_type->cal_blocks) { cal_block = list_entry(ptr, struct cal_block_data, list); break; } done: return cal_block; } EXPORT_SYMBOL(cal_utils_get_only_cal_block); /** * cal_utils_get_only_cal_block * * @cal_block: pointer to cal block struct * @user_data: pointer to user data * * Returns true on match */ bool cal_utils_match_buf_num(struct cal_block_data *cal_block, void *user_data) { bool ret = false; struct audio_cal_type_basic *data = user_data; if (cal_block->buffer_number == data->cal_hdr.buffer_number) ret = true; return ret; } EXPORT_SYMBOL(cal_utils_match_buf_num); static struct cal_block_data *get_matching_cal_block( struct cal_type_data *cal_type, void *data) { struct list_head *ptr, *next; struct cal_block_data *cal_block = NULL; list_for_each_safe(ptr, next, &cal_type->cal_blocks) { cal_block = list_entry(ptr, struct cal_block_data, list); if (cal_type->info.cal_util_callbacks. match_block(cal_block, data)) return cal_block; } return NULL; } static int cal_block_ion_alloc(struct cal_block_data *cal_block) { int ret = 0; if (cal_block == NULL) { pr_err("%s: cal_block is NULL!\n", __func__); ret = -EINVAL; goto done; } if (cal_block->cma_mem) { ret = msm_audio_ion_import_cma(&cal_block->map_data.dma_buf, cal_block->map_data.ion_map_handle, NULL, 0, &cal_block->cal_data.paddr, &cal_block->map_data.map_size, &cal_block->cal_data.kvaddr); } else { ret = msm_audio_ion_import(&cal_block->map_data.dma_buf, cal_block->map_data.ion_map_handle, NULL, 0, &cal_block->cal_data.paddr, &cal_block->map_data.map_size, &cal_block->cal_data.kvaddr); } if (ret) { pr_err("%s: audio ION import failed, rc = %d\n", __func__, ret); ret = -ENOMEM; goto done; } done: return ret; } static struct cal_block_data *create_cal_block(struct cal_type_data *cal_type, struct audio_cal_type_basic *basic_cal, size_t client_info_size, void *client_info) { struct cal_block_data *cal_block = NULL; if (cal_type == NULL) { pr_err("%s: cal_type is NULL!\n", __func__); goto done; } else if (basic_cal == NULL) { pr_err("%s: basic_cal is NULL!\n", __func__); goto done; } cal_block = kzalloc(sizeof(*cal_block), GFP_KERNEL); if (cal_block == NULL) goto done; INIT_LIST_HEAD(&cal_block->list); cal_block->map_data.ion_map_handle = basic_cal->cal_data.mem_handle; cal_block->cma_mem = basic_cal->cal_data.cma_mem; if (basic_cal->cal_data.mem_handle > 0) { if (cal_block_ion_alloc(cal_block)) { pr_err("%s: cal_block_ion_alloc failed!\n", __func__); goto err; } } if (client_info_size > 0) { cal_block->client_info_size = client_info_size; cal_block->client_info = kmalloc(client_info_size, GFP_KERNEL); if (cal_block->client_info == NULL) { pr_err("%s: could not allocats client_info!\n", __func__); goto err; } if (client_info != NULL) memcpy(cal_block->client_info, client_info, client_info_size); } cal_block->cal_info = kzalloc( get_cal_info_size(cal_type->info.reg.cal_type), GFP_KERNEL); if (cal_block->cal_info == NULL) { pr_err("%s: could not allocats cal_info!\n", __func__); goto err; } cal_block->buffer_number = basic_cal->cal_hdr.buffer_number; list_add_tail(&cal_block->list, &cal_type->cal_blocks); pr_debug("%s: created block for cal type %d, buf num %d, map handle %d, map size %zd paddr 0x%pK!\n", __func__, cal_type->info.reg.cal_type, cal_block->buffer_number, cal_block->map_data.ion_map_handle, cal_block->map_data.map_size, &cal_block->cal_data.paddr); done: return cal_block; err: kfree(cal_block->cal_info); cal_block->cal_info = NULL; kfree(cal_block->client_info); cal_block->client_info = NULL; kfree(cal_block); cal_block = NULL; return cal_block; } void cal_utils_clear_cal_block_q6maps(int num_cal_types, struct cal_type_data **cal_type) { int i = 0; struct list_head *ptr, *next; struct cal_block_data *cal_block; pr_debug("%s\n", __func__); if (cal_type == NULL) { pr_err("%s: cal_type is NULL!\n", __func__); goto done; } else if ((num_cal_types <= 0) || (num_cal_types > MAX_CAL_TYPES)) { pr_err("%s: num_cal_types of %d is Invalid!\n", __func__, num_cal_types); goto done; } for (; i < num_cal_types; i++) { if (cal_type[i] == NULL) continue; mutex_lock(&cal_type[i]->lock); list_for_each_safe(ptr, next, &cal_type[i]->cal_blocks) { cal_block = list_entry(ptr, struct cal_block_data, list); cal_block->map_data.q6map_handle = 0; } mutex_unlock(&cal_type[i]->lock); } done: return; } static int realloc_memory(struct cal_block_data *cal_block) { int ret = 0; if (cal_block->cma_mem) msm_audio_ion_free_cma(cal_block->map_data.dma_buf); else msm_audio_ion_free(cal_block->map_data.dma_buf); cal_block->map_data.dma_buf = NULL; cal_block->cal_data.size = 0; ret = cal_block_ion_alloc(cal_block); if (ret < 0) pr_err("%s: realloc_memory failed!\n", __func__); return ret; } static int map_memory(struct cal_type_data *cal_type, struct cal_block_data *cal_block) { int ret = 0; if (cal_type->info.cal_util_callbacks.map_cal != NULL) { if ((cal_block->map_data.ion_map_handle < 0) || (cal_block->map_data.map_size <= 0) || (cal_block->map_data.q6map_handle != 0)) { goto done; } pr_debug("%s: cal type %d call map\n", __func__, cal_type->info.reg.cal_type); ret = cal_type->info.cal_util_callbacks. map_cal(cal_type->info.reg.cal_type, cal_block); if (ret < 0) { pr_err("%s: map_cal failed, cal type %d, ret = %d!\n", __func__, cal_type->info.reg.cal_type, ret); goto done; } } done: return ret; } static int unmap_memory(struct cal_type_data *cal_type, struct cal_block_data *cal_block) { int ret = 0; if (cal_type->info.cal_util_callbacks.unmap_cal != NULL) { if ((cal_block->map_data.ion_map_handle < 0) || (cal_block->map_data.map_size <= 0) || (cal_block->map_data.q6map_handle == 0)) { goto done; } pr_debug("%s: cal type %d call unmap\n", __func__, cal_type->info.reg.cal_type); ret = cal_type->info.cal_util_callbacks. unmap_cal(cal_type->info.reg.cal_type, cal_block); if (ret < 0) { pr_err("%s: unmap_cal failed, cal type %d, ret = %d!\n", __func__, cal_type->info.reg.cal_type, ret); goto done; } } done: return ret; } /** * cal_utils_alloc_cal * * @data_size: size of data to allocate * @data: data pointer * @cal_type: pointer to the cal type * @client_info_size: client info size * @client_info: pointer to client info * * Returns 0 on success, appropriate error code otherwise */ int cal_utils_alloc_cal(size_t data_size, void *data, struct cal_type_data *cal_type, size_t client_info_size, void *client_info) { int ret = 0; struct cal_block_data *cal_block; struct audio_cal_type_alloc *alloc_data = data; pr_debug("%s\n", __func__); if (cal_type == NULL) { pr_err("%s: cal_type is NULL!\n", __func__); ret = -EINVAL; goto done; } if (data_size < sizeof(struct audio_cal_type_alloc)) { pr_err("%s: data_size of %zd does not equal alloc struct size of %zd!\n", __func__, data_size, sizeof(struct audio_cal_type_alloc)); ret = -EINVAL; goto done; } if ((client_info_size > 0) && (client_info == NULL)) { pr_err("%s: User info pointer is NULL but size is %zd!\n", __func__, client_info_size); ret = -EINVAL; goto done; } if (alloc_data->cal_data.mem_handle < 0) { pr_err("%s: mem_handle %d invalid!\n", __func__, alloc_data->cal_data.mem_handle); ret = -EINVAL; goto done; } mutex_lock(&cal_type->lock); cal_block = get_matching_cal_block(cal_type, data); if (cal_block != NULL) { cal_block->cma_mem = alloc_data->cal_data.cma_mem; ret = unmap_memory(cal_type, cal_block); if (ret < 0) goto err; ret = realloc_memory(cal_block); if (ret < 0) goto err; } else { cal_block = create_cal_block(cal_type, (struct audio_cal_type_basic *)alloc_data, client_info_size, client_info); if (cal_block == NULL) { pr_err("%s: create_cal_block failed for %d!\n", __func__, alloc_data->cal_data.mem_handle); ret = -EINVAL; goto err; } } ret = map_memory(cal_type, cal_block); if (ret < 0) goto err; err: mutex_unlock(&cal_type->lock); done: return ret; } EXPORT_SYMBOL(cal_utils_alloc_cal); /** * cal_utils_dealloc_cal * * @data_size: size of data to allocate * @data: data pointer * @cal_type: pointer to the cal type * * Returns 0 on success, appropriate error code otherwise */ int cal_utils_dealloc_cal(size_t data_size, void *data, struct cal_type_data *cal_type) { int ret = 0; struct cal_block_data *cal_block; struct audio_cal_type_dealloc *dealloc_data = data; pr_debug("%s\n", __func__); if (cal_type == NULL) { pr_err("%s: cal_type is NULL!\n", __func__); ret = -EINVAL; goto done; } if (data_size < sizeof(struct audio_cal_type_dealloc)) { pr_err("%s: data_size of %zd does not equal struct size of %zd!\n", __func__, data_size, sizeof(struct audio_cal_type_dealloc)); ret = -EINVAL; goto done; } if ((dealloc_data->cal_data.mem_handle == -1) && (dealloc_data->cal_hdr.buffer_number == ALL_CAL_BLOCKS)) { destroy_all_cal_blocks(cal_type); goto done; } if (dealloc_data->cal_data.mem_handle < 0) { pr_err("%s: mem_handle %d invalid!\n", __func__, dealloc_data->cal_data.mem_handle); ret = -EINVAL; goto done; } mutex_lock(&cal_type->lock); cal_block = get_matching_cal_block( cal_type, data); if (cal_block == NULL) { pr_err("%s: allocation does not exist for %d!\n", __func__, dealloc_data->cal_data.mem_handle); ret = -EINVAL; goto err; } ret = unmap_memory(cal_type, cal_block); if (ret < 0) goto err; mutex_lock(&cal_lock); delete_cal_block(cal_block); mutex_unlock(&cal_lock); err: mutex_unlock(&cal_type->lock); done: return ret; } EXPORT_SYMBOL(cal_utils_dealloc_cal); /** * cal_utils_set_cal * * @data_size: size of data to allocate * @data: data pointer * @cal_type: pointer to the cal type * @client_info_size: client info size * @client_info: pointer to client info * * Returns 0 on success, appropriate error code otherwise */ int cal_utils_set_cal(size_t data_size, void *data, struct cal_type_data *cal_type, size_t client_info_size, void *client_info) { int ret = 0; struct cal_block_data *cal_block; struct audio_cal_type_basic *basic_data = data; pr_debug("%s\n", __func__); if (cal_type == NULL) { pr_err("%s: cal_type is NULL!\n", __func__); ret = -EINVAL; goto done; } if ((client_info_size > 0) && (client_info == NULL)) { pr_err("%s: User info pointer is NULL but size is %zd!\n", __func__, client_info_size); ret = -EINVAL; goto done; } if ((data_size > get_user_cal_type_size( cal_type->info.reg.cal_type)) || (data_size < 0)) { pr_err("%s: cal_type %d, data_size of %zd is invalid, expecting %zd!\n", __func__, cal_type->info.reg.cal_type, data_size, get_user_cal_type_size(cal_type->info.reg.cal_type)); ret = -EINVAL; goto done; } mutex_lock(&cal_type->lock); cal_block = get_matching_cal_block( cal_type, data); if (cal_block == NULL) { if (basic_data->cal_data.mem_handle > 0) { pr_err("%s: allocation does not exist for %d!\n", __func__, basic_data->cal_data.mem_handle); ret = -EINVAL; goto err; } else { cal_block = create_cal_block( cal_type, basic_data, client_info_size, client_info); if (cal_block == NULL) { pr_err("%s: create_cal_block failed for cal type %d!\n", __func__, cal_type->info.reg.cal_type); ret = -EINVAL; goto err; } } } ret = map_memory(cal_type, cal_block); if (ret < 0) goto err; cal_block->cal_data.size = basic_data->cal_data.cal_size; if (client_info_size > 0) { memcpy(cal_block->client_info, client_info, client_info_size); } memcpy(cal_block->cal_info, ((uint8_t *)data + sizeof(struct audio_cal_type_basic)), data_size - sizeof(struct audio_cal_type_basic)); /* reset buffer stale flag */ cal_block->cal_stale = false; err: mutex_unlock(&cal_type->lock); done: return ret; } EXPORT_SYMBOL(cal_utils_set_cal); /** * cal_utils_mark_cal_used * * @cal_block: pointer to cal block */ void cal_utils_mark_cal_used(struct cal_block_data *cal_block) { if (cal_block) cal_block->cal_stale = true; } EXPORT_SYMBOL(cal_utils_mark_cal_used); int __init cal_utils_init(void) { mutex_init(&cal_lock); return 0; } /** * cal_utils_is_cal_stale * * @cal_block: pointer to cal block * * Returns true if cal block is stale, false otherwise */ bool cal_utils_is_cal_stale(struct cal_block_data *cal_block) { bool ret = false; mutex_lock(&cal_lock); if (!cal_block) { pr_err("%s: cal_block is Null", __func__); goto unlock; } if (cal_block->cal_stale) ret = true; unlock: mutex_unlock(&cal_lock); return ret; } EXPORT_SYMBOL(cal_utils_is_cal_stale);